mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 07:23:00 +02:00
Merge pull request #3775 from birarda/lobby
repairs to local audio injection
This commit is contained in:
commit
331e9d6558
42 changed files with 535 additions and 300 deletions
|
@ -132,15 +132,16 @@ function checkHands(deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function playChord(position, volume) {
|
function playChord(position, volume) {
|
||||||
var options = new AudioInjectionOptions();
|
|
||||||
options.position = position;
|
|
||||||
options.volume = volume;
|
|
||||||
if (Audio.isInjectorPlaying(soundPlaying)) {
|
if (Audio.isInjectorPlaying(soundPlaying)) {
|
||||||
print("stopped sound");
|
print("stopped sound");
|
||||||
Audio.stopInjector(soundPlaying);
|
Audio.stopInjector(soundPlaying);
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Played sound: " + whichChord + " at volume " + options.volume);
|
print("Played sound: " + whichChord + " at volume " + options.volume);
|
||||||
soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], options);
|
soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], {
|
||||||
|
position: position,
|
||||||
|
volume: volume
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyPressEvent(event) {
|
function keyPressEvent(event) {
|
||||||
|
|
|
@ -32,10 +32,10 @@ function updateEntity(deltaTime) {
|
||||||
|
|
||||||
if (Math.random() < CHANCE_OF_PLAYING_SOUND) {
|
if (Math.random() < CHANCE_OF_PLAYING_SOUND) {
|
||||||
// play a sound at the location of the entity
|
// play a sound at the location of the entity
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(sound, {
|
||||||
options.position = entityPosition;
|
position: entityPosition,
|
||||||
options.volume = 0.75;
|
volume: 0.75
|
||||||
Audio.playSound(sound, options);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR;
|
var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR;
|
||||||
|
|
|
@ -17,9 +17,11 @@ var SOUND_TRIGGER_CLEAR = 1000; // milliseconds
|
||||||
var SOUND_TRIGGER_DELAY = 200; // milliseconds
|
var SOUND_TRIGGER_DELAY = 200; // milliseconds
|
||||||
var soundExpiry = 0;
|
var soundExpiry = 0;
|
||||||
var DateObj = new Date();
|
var DateObj = new Date();
|
||||||
var audioOptions = new AudioInjectionOptions();
|
|
||||||
audioOptions.volume = 0.5;
|
var audioOptions = {
|
||||||
audioOptions.position = { x: 0, y: 0, z: 0 };
|
volume: 0.5,
|
||||||
|
position: { x: 0, y: 0, z: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
var hitSounds = new Array();
|
var hitSounds = new Array();
|
||||||
hitSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw");
|
hitSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw");
|
||||||
|
|
|
@ -33,20 +33,22 @@ function maybePlaySound(deltaTime) {
|
||||||
// Set the location and other info for the sound to play
|
// Set the location and other info for the sound to play
|
||||||
var whichBird = Math.floor(Math.random() * birds.length);
|
var whichBird = Math.floor(Math.random() * birds.length);
|
||||||
//print("playing sound # " + whichBird);
|
//print("playing sound # " + whichBird);
|
||||||
var options = new AudioInjectionOptions();
|
var position = {
|
||||||
var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x),
|
x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x),
|
||||||
y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y),
|
y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y),
|
||||||
z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) };
|
z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z)
|
||||||
options.position = position;
|
};
|
||||||
options.volume = BIRD_MASTER_VOLUME;
|
var options = {
|
||||||
//
|
position: position,
|
||||||
|
volume: BIRD_MASTER_VOLUME
|
||||||
|
};
|
||||||
var entityId = Entities.addEntity({
|
var entityId = Entities.addEntity({
|
||||||
type: "Sphere",
|
type: "Sphere",
|
||||||
position: position,
|
position: position,
|
||||||
dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE },
|
dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE },
|
||||||
color: birds[whichBird].color,
|
color: birds[whichBird].color,
|
||||||
lifetime: 10
|
lifetime: 10
|
||||||
});
|
});
|
||||||
|
|
||||||
if (useLights) {
|
if (useLights) {
|
||||||
var lightId = Entities.addEntity({
|
var lightId = Entities.addEntity({
|
||||||
|
|
|
@ -172,13 +172,11 @@ function playRandomSound() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function playRandomFootstepSound() {
|
function playRandomFootstepSound() {
|
||||||
|
var whichSound = Math.floor((Math.random() * footstepSounds.length));
|
||||||
var whichSound = Math.floor((Math.random() * footstepSounds.length));
|
Audio.playSound(footstepSounds[whichSound], {
|
||||||
var options = new AudioInjectionOptions();
|
position: Avatar.position,
|
||||||
options.position = Avatar.position;
|
volume: 1.0
|
||||||
options.volume = 1.0;
|
});
|
||||||
Audio.playSound(footstepSounds[whichSound], options);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Facial Animation
|
// Facial Animation
|
||||||
|
|
|
@ -134,13 +134,11 @@ function playRandomSound() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function playRandomFootstepSound() {
|
function playRandomFootstepSound() {
|
||||||
|
var whichSound = Math.floor((Math.random() * footstepSounds.length));
|
||||||
var whichSound = Math.floor((Math.random() * footstepSounds.length));
|
Audio.playSound(footstepSounds[whichSound], {
|
||||||
var options = new AudioInjectionOptions();
|
position: Avatar.position,
|
||||||
options.position = Avatar.position;
|
volume: 1.0
|
||||||
options.volume = 1.0;
|
});
|
||||||
Audio.playSound(footstepSounds[whichSound], options);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************************************ Facial Animation **********************************
|
// ************************************ Facial Animation **********************************
|
||||||
|
|
|
@ -89,11 +89,11 @@ function maybePlaySound(deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function playClap(volume, position) {
|
function playClap(volume, position) {
|
||||||
var options = new AudioInjectionOptions();
|
|
||||||
options.position = position;
|
|
||||||
options.volume = 1.0;
|
|
||||||
var clip = Math.floor(Math.random() * numberOfSounds);
|
var clip = Math.floor(Math.random() * numberOfSounds);
|
||||||
Audio.playSound(claps[clip], options);
|
Audio.playSound(claps[clip], {
|
||||||
|
position: position,
|
||||||
|
volume: volume
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var FASTEST_CLAP_INTERVAL = 150.0;
|
var FASTEST_CLAP_INTERVAL = 150.0;
|
||||||
|
|
|
@ -63,8 +63,11 @@ function checkSticks(deltaTime) {
|
||||||
// Waiting for change in velocity direction or slowing to trigger drum sound
|
// Waiting for change in velocity direction or slowing to trigger drum sound
|
||||||
if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) {
|
if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) {
|
||||||
state[palm] = 0;
|
state[palm] = 0;
|
||||||
var options = new AudioInjectionOptions();
|
|
||||||
options.position = Controller.getSpatialControlPosition(palm * 2 + 1);
|
var options = {
|
||||||
|
position: Controller.getSpatialControlPosition(palm * 2 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; }
|
if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; }
|
||||||
options.volume = strokeSpeed[palm];
|
options.volume = strokeSpeed[palm];
|
||||||
|
|
||||||
|
|
|
@ -68,9 +68,11 @@ var numColors = 9;
|
||||||
var whichColor = 0; // Starting color is 'Copy' mode
|
var whichColor = 0; // Starting color is 'Copy' mode
|
||||||
|
|
||||||
// Create sounds for for every script actions that require one
|
// Create sounds for for every script actions that require one
|
||||||
var audioOptions = new AudioInjectionOptions();
|
// start with audio slightly above the avatar
|
||||||
audioOptions.volume = 1.0;
|
var audioOptions = {
|
||||||
audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ); // start with audio slightly above the avatar
|
position: Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ),
|
||||||
|
volume: 1.0
|
||||||
|
};
|
||||||
|
|
||||||
function SoundArray() {
|
function SoundArray() {
|
||||||
this.audioOptions = audioOptions
|
this.audioOptions = audioOptions
|
||||||
|
|
|
@ -135,10 +135,10 @@ function updateBirds(deltaTime) {
|
||||||
// Tweeting behavior
|
// Tweeting behavior
|
||||||
if (birds[i].tweeting == 0) {
|
if (birds[i].tweeting == 0) {
|
||||||
if (Math.random() < CHANCE_OF_TWEETING) {
|
if (Math.random() < CHANCE_OF_TWEETING) {
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(birds[i].tweetSound, {
|
||||||
options.position = properties.position;
|
position: properties.position,
|
||||||
options.volume = 0.75;
|
volume: 0.75
|
||||||
Audio.playSound(birds[i].tweetSound, options);
|
});
|
||||||
birds[i].tweeting = 10;
|
birds[i].tweeting = 10;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,14 +14,6 @@
|
||||||
(function(){
|
(function(){
|
||||||
var bird;
|
var bird;
|
||||||
|
|
||||||
function playSound(entityID) {
|
|
||||||
var options = new AudioInjectionOptions();
|
|
||||||
var position = MyAvatar.position;
|
|
||||||
options.position = position;
|
|
||||||
options.volume = 0.5;
|
|
||||||
Audio.playSound(bird, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
print("preload("+entityID.id+")");
|
print("preload("+entityID.id+")");
|
||||||
bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
||||||
|
@ -29,6 +21,9 @@
|
||||||
|
|
||||||
this.clickDownOnEntity = function(entityID, mouseEvent) {
|
this.clickDownOnEntity = function(entityID, mouseEvent) {
|
||||||
print("clickDownOnEntity()...");
|
print("clickDownOnEntity()...");
|
||||||
playSound();
|
Audio.playSound(bird, {
|
||||||
|
position: MyAvatar.position,
|
||||||
|
volume: 0.5
|
||||||
|
});
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,13 +14,12 @@
|
||||||
(function(){
|
(function(){
|
||||||
var bird;
|
var bird;
|
||||||
|
|
||||||
function playSound() {
|
function playSound(entityID) {
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(bird, {
|
||||||
var position = MyAvatar.position;
|
position: MyAvatar.position,
|
||||||
options.position = position;
|
volume: 0.5
|
||||||
options.volume = 0.5;
|
});
|
||||||
Audio.playSound(bird, options);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
print("preload("+entityID.id+")");
|
print("preload("+entityID.id+")");
|
||||||
|
@ -31,7 +30,7 @@
|
||||||
playSound();
|
playSound();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.leaveEntity = function(entityID) {
|
this.leaveEntity = function(entityID) {
|
||||||
playSound();
|
playSound();
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -177,10 +177,10 @@ function playSound(sound, position) {
|
||||||
if (!SOUNDS_ENABLED) {
|
if (!SOUNDS_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var options = new AudioInjectionOptions();
|
|
||||||
options.position = position;
|
Audio.playSound(sound,{
|
||||||
options.volume = 1.0;
|
position: position
|
||||||
Audio.playSound(sound, options);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanupFrisbees() {
|
function cleanupFrisbees() {
|
||||||
|
|
|
@ -44,8 +44,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/
|
||||||
|
|
||||||
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
||||||
|
|
||||||
var audioOptions = new AudioInjectionOptions();
|
var audioOptions {
|
||||||
audioOptions.volume = 0.9;
|
volume: 0.9
|
||||||
|
}
|
||||||
|
|
||||||
var shotsFired = 0;
|
var shotsFired = 0;
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/
|
||||||
|
|
||||||
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
||||||
|
|
||||||
var audioOptions = new AudioInjectionOptions();
|
var audioOptions = {
|
||||||
audioOptions.volume = 0.9;
|
volume: 0.9
|
||||||
|
}
|
||||||
|
|
||||||
var shotsFired = 0;
|
var shotsFired = 0;
|
||||||
|
|
||||||
|
|
|
@ -72,15 +72,11 @@ var WATCH_AVATAR_DISTANCE = 2.5;
|
||||||
|
|
||||||
var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav");
|
var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav");
|
||||||
function playSound() {
|
function playSound() {
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(sound, {
|
||||||
var position = MyAvatar.position;
|
position: MyAvatar.position
|
||||||
options.position = position;
|
});
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(sound, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function pullBack() {
|
function pullBack() {
|
||||||
saveCameraState();
|
saveCameraState();
|
||||||
cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -hipsToEyes, z: -hipsToEyes * WATCH_AVATAR_DISTANCE }));
|
cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -hipsToEyes, z: -hipsToEyes * WATCH_AVATAR_DISTANCE }));
|
||||||
|
|
|
@ -19,11 +19,9 @@ var soundPlaying = false;
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
if (!Audio.isInjectorPlaying(soundPlaying)) {
|
if (!Audio.isInjectorPlaying(soundPlaying)) {
|
||||||
var options = new AudioInjectionOptions();
|
soundPlaying = Audio.playSound(sound, {
|
||||||
options.position = { x:0, y:0, z:0 };
|
loop: true
|
||||||
options.volume = 1.0;
|
});
|
||||||
options.loop = true;
|
|
||||||
soundPlaying = Audio.playSound(sound, options);
|
|
||||||
print("Started sound loop");
|
print("Started sound loop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,14 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter);
|
||||||
|
|
||||||
var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8};
|
var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8};
|
||||||
|
|
||||||
var HELMET_ATTACHMENT_URL = "https://hifi-public.s3.amazonaws.com/models/attachments/IronManMaskOnly.fbx"
|
var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx"
|
||||||
|
|
||||||
|
var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw")
|
||||||
|
var currentDrone = null;
|
||||||
|
|
||||||
|
var latinSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw")
|
||||||
|
var elevatorSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.raw")
|
||||||
|
var currentMusak = null;
|
||||||
|
|
||||||
function reticlePosition() {
|
function reticlePosition() {
|
||||||
var RETICLE_DISTANCE = 1;
|
var RETICLE_DISTANCE = 1;
|
||||||
|
@ -87,6 +94,12 @@ function drawLobby() {
|
||||||
|
|
||||||
// add an attachment on this avatar so other people see them in the lobby
|
// add an attachment on this avatar so other people see them in the lobby
|
||||||
MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15);
|
MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15);
|
||||||
|
|
||||||
|
// start the drone sound
|
||||||
|
currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true });
|
||||||
|
|
||||||
|
// start one of our musak sounds
|
||||||
|
playRandomMusak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +125,35 @@ function changeLobbyTextures() {
|
||||||
Overlays.editOverlay(panelWall, textureProp);
|
Overlays.editOverlay(panelWall, textureProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function playRandomMusak() {
|
||||||
|
chosenSound = null;
|
||||||
|
|
||||||
|
if (latinSound.downloaded && elevatorSound.downloaded) {
|
||||||
|
chosenSound = Math.random < 0.5 ? latinSound : elevatorSound;
|
||||||
|
} else if (latinSound.downloaded) {
|
||||||
|
chosenSound = latinSound;
|
||||||
|
} else if (elevatorSound.downloaded) {
|
||||||
|
chosenSound = elevatorSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chosenSound) {
|
||||||
|
currentMusak = Audio.playSound(chosenSound, { stereo: true, localOnly: true })
|
||||||
|
} else {
|
||||||
|
currentMusak = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cleanupLobby() {
|
function cleanupLobby() {
|
||||||
Overlays.deleteOverlay(panelWall);
|
Overlays.deleteOverlay(panelWall);
|
||||||
Overlays.deleteOverlay(orbShell);
|
Overlays.deleteOverlay(orbShell);
|
||||||
Overlays.deleteOverlay(reticle);
|
Overlays.deleteOverlay(reticle);
|
||||||
|
|
||||||
|
Audio.stopInjector(currentDrone);
|
||||||
|
currentDrone = null;
|
||||||
|
|
||||||
|
Audio.stopInjector(currentMusak);
|
||||||
|
currentMusak = null;
|
||||||
|
|
||||||
panelWall = false;
|
panelWall = false;
|
||||||
orbShell = false;
|
orbShell = false;
|
||||||
reticle = false;
|
reticle = false;
|
||||||
|
|
|
@ -15,12 +15,11 @@ var bird = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw");
|
||||||
|
|
||||||
function maybePlaySound(deltaTime) {
|
function maybePlaySound(deltaTime) {
|
||||||
if (Math.random() < 0.01) {
|
if (Math.random() < 0.01) {
|
||||||
// Set the location and other info for the sound to play
|
// Set the location and other info for the sound to play
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(bird, {
|
||||||
var position = MyAvatar.position;
|
position: MyAvatar.position,
|
||||||
options.position = position;
|
volume: 0.5
|
||||||
options.volume = 0.5;
|
});
|
||||||
Audio.playSound(bird, options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,12 @@ var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw"
|
||||||
//var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav");
|
//var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav");
|
||||||
|
|
||||||
var soundPlaying = false;
|
var soundPlaying = false;
|
||||||
var options = new AudioInjectionOptions();
|
var options = {
|
||||||
options.position = Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation));
|
position: Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation)),
|
||||||
options.volume = 0.5;
|
volume: 0.5,
|
||||||
options.loop = true;
|
loop: true
|
||||||
|
}
|
||||||
|
|
||||||
var playing = false;
|
var playing = false;
|
||||||
var ball = false;
|
var ball = false;
|
||||||
|
|
||||||
|
|
|
@ -19,24 +19,23 @@ var distance = 1;
|
||||||
var debug = 0;
|
var debug = 0;
|
||||||
|
|
||||||
function playSound() {
|
function playSound() {
|
||||||
var options = new AudioInjectionOptions();
|
currentTime += deltaTime;
|
||||||
currentTime += deltaTime;
|
|
||||||
|
|
||||||
var s = distance * Math.sin(currentTime);
|
var s = distance * Math.sin(currentTime);
|
||||||
var c = distance * Math.cos(currentTime);
|
var c = distance * Math.cos(currentTime);
|
||||||
|
|
||||||
var soundOffset = { x:s, y:0, z:c };
|
var soundOffset = { x:s, y:0, z:c };
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z);
|
print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
var avatarPosition = MyAvatar.position;
|
var avatarPosition = MyAvatar.position;
|
||||||
var soundPosition = Vec3.sum(avatarPosition,soundOffset);
|
var soundPosition = Vec3.sum(avatarPosition,soundOffset);
|
||||||
|
|
||||||
options.position = soundPosition
|
Audio.playSound(soundClip, {
|
||||||
options.volume = 1.0;
|
position: soundPosition
|
||||||
Audio.playSound(soundClip, options);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.setInterval(playSound, 250);
|
Script.setInterval(playSound, 250);
|
||||||
|
|
|
@ -14,11 +14,10 @@ Script.include("libraries/globals.js");
|
||||||
var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav");
|
var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav");
|
||||||
|
|
||||||
function playSound() {
|
function playSound() {
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(soundClip, {
|
||||||
var position = MyAvatar.position;
|
position: MyAvatar.position,
|
||||||
options.position = position;
|
volume: 0.5
|
||||||
options.volume = 0.5;
|
});
|
||||||
Audio.playSound(soundClip, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.setInterval(playSound, 10000);
|
Script.setInterval(playSound, 10000);
|
||||||
|
|
|
@ -15,10 +15,12 @@ var modelURL = HIFI_PUBLIC_BUCKET + "models/entities/radio/Speakers.fbx";
|
||||||
var soundURL = HIFI_PUBLIC_BUCKET + "sounds/FamilyStereo.raw";
|
var soundURL = HIFI_PUBLIC_BUCKET + "sounds/FamilyStereo.raw";
|
||||||
|
|
||||||
var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0);
|
var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0);
|
||||||
var audioOptions = new AudioInjectionOptions();
|
var audioOptions = {
|
||||||
audioOptions.volume = 0.5;
|
volume: 0.5,
|
||||||
audioOptions.loop = true;
|
loop: true,
|
||||||
audioOptions.isStereo = true;
|
stereo: true
|
||||||
|
}
|
||||||
|
|
||||||
var injector = null;
|
var injector = null;
|
||||||
|
|
||||||
var sound = new Sound(soundURL, audioOptions.isStereo);
|
var sound = new Sound(soundURL, audioOptions.isStereo);
|
||||||
|
|
|
@ -217,7 +217,8 @@ function update(deltaTime) {
|
||||||
|
|
||||||
if (invaderStepOfCycle % stepsPerSound == 0) {
|
if (invaderStepOfCycle % stepsPerSound == 0) {
|
||||||
// play the move sound
|
// play the move sound
|
||||||
var options = new AudioInjectionOptions();
|
var options = {};
|
||||||
|
|
||||||
if (soundInMyHead) {
|
if (soundInMyHead) {
|
||||||
options.position = { x: MyAvatar.position.x + 0.0,
|
options.position = { x: MyAvatar.position.x + 0.0,
|
||||||
y: MyAvatar.position.y + 0.1,
|
y: MyAvatar.position.y + 0.1,
|
||||||
|
@ -225,7 +226,7 @@ function update(deltaTime) {
|
||||||
} else {
|
} else {
|
||||||
options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2);
|
options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2);
|
||||||
}
|
}
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(moveSounds[currentMoveSound], options);
|
Audio.playSound(moveSounds[currentMoveSound], options);
|
||||||
|
|
||||||
// get ready for next move sound
|
// get ready for next move sound
|
||||||
|
@ -330,7 +331,7 @@ function fireMissile() {
|
||||||
lifetime: 5
|
lifetime: 5
|
||||||
});
|
});
|
||||||
|
|
||||||
var options = new AudioInjectionOptions();
|
var options = {}
|
||||||
if (soundInMyHead) {
|
if (soundInMyHead) {
|
||||||
options.position = { x: MyAvatar.position.x + 0.0,
|
options.position = { x: MyAvatar.position.x + 0.0,
|
||||||
y: MyAvatar.position.y + 0.1,
|
y: MyAvatar.position.y + 0.1,
|
||||||
|
@ -338,7 +339,7 @@ function fireMissile() {
|
||||||
} else {
|
} else {
|
||||||
options.position = missilePosition;
|
options.position = missilePosition;
|
||||||
}
|
}
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(shootSound, options);
|
Audio.playSound(shootSound, options);
|
||||||
|
|
||||||
missileFired = true;
|
missileFired = true;
|
||||||
|
@ -380,7 +381,7 @@ function deleteIfInvader(possibleInvaderEntity) {
|
||||||
Entities.deleteEntity(myMissile);
|
Entities.deleteEntity(myMissile);
|
||||||
|
|
||||||
// play the hit sound
|
// play the hit sound
|
||||||
var options = new AudioInjectionOptions();
|
var options = {};
|
||||||
if (soundInMyHead) {
|
if (soundInMyHead) {
|
||||||
options.position = { x: MyAvatar.position.x + 0.0,
|
options.position = { x: MyAvatar.position.x + 0.0,
|
||||||
y: MyAvatar.position.y + 0.1,
|
y: MyAvatar.position.y + 0.1,
|
||||||
|
@ -388,7 +389,7 @@ function deleteIfInvader(possibleInvaderEntity) {
|
||||||
} else {
|
} else {
|
||||||
options.position = getInvaderPosition(row, column);
|
options.position = getInvaderPosition(row, column);
|
||||||
}
|
}
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(hitSound, options);
|
Audio.playSound(hitSound, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,10 +113,7 @@ function checkControllerSide(whichSide) {
|
||||||
inHand: true };
|
inHand: true };
|
||||||
Entities.editEntity(closestEntity, properties);
|
Entities.editEntity(closestEntity, properties);
|
||||||
|
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(catchSound, { position: ballPosition });
|
||||||
options.position = ballPosition;
|
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(catchSound, options);
|
|
||||||
|
|
||||||
return; // exit early
|
return; // exit early
|
||||||
}
|
}
|
||||||
|
@ -156,10 +153,7 @@ function checkControllerSide(whichSide) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play a new ball sound
|
// Play a new ball sound
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(newSound, { position: ballPosition});
|
||||||
options.position = ballPosition;
|
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(newSound, options);
|
|
||||||
|
|
||||||
return; // exit early
|
return; // exit early
|
||||||
}
|
}
|
||||||
|
@ -207,10 +201,7 @@ function checkControllerSide(whichSide) {
|
||||||
rightHandEntity = false;
|
rightHandEntity = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = new AudioInjectionOptions();
|
Audio.playSound(throwSound, { position: ballPosition });
|
||||||
options.position = ballPosition;
|
|
||||||
options.volume = 1.0;
|
|
||||||
Audio.playSound(throwSound, options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,6 @@ Script.update.connect(function(deltaTime) {
|
||||||
animateAvatar(deltaTime, speed);
|
animateAvatar(deltaTime, speed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case state.EDIT_STANDING: {
|
case state.EDIT_STANDING: {
|
||||||
motion.curAnim = motion.selStand;
|
motion.curAnim = motion.selStand;
|
||||||
motion.direction = FORWARDS;
|
motion.direction = FORWARDS;
|
||||||
|
@ -559,9 +558,11 @@ function getLeanRoll(deltaTime, speed) {
|
||||||
|
|
||||||
function playFootstep(side) {
|
function playFootstep(side) {
|
||||||
|
|
||||||
var options = new AudioInjectionOptions();
|
options = {
|
||||||
options.position = Camera.getPosition();
|
position: Camera.getPosition(),
|
||||||
options.volume = 0.3;
|
volume: 0.3
|
||||||
|
}
|
||||||
|
|
||||||
var soundNumber = 2; // 0 to 2
|
var soundNumber = 2; // 0 to 2
|
||||||
if (side === RIGHT && motion.makesFootStepSounds) {
|
if (side === RIGHT && motion.makesFootStepSounds) {
|
||||||
Audio.playSound(walkAssets.footsteps[soundNumber + 1], options);
|
Audio.playSound(walkAssets.footsteps[soundNumber + 1], options);
|
||||||
|
@ -2609,4 +2610,4 @@ function animateAvatar(deltaTime, speed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin by setting an internal state
|
// Begin by setting an internal state
|
||||||
state.setInternalState(state.STANDING);
|
state.setInternalState(state.STANDING);
|
||||||
|
|
|
@ -418,7 +418,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_trayIcon->show();
|
_trayIcon->show();
|
||||||
|
|
||||||
// set the local loopback interface for local sounds from audio scripts
|
// set the local loopback interface for local sounds from audio scripts
|
||||||
AudioScriptingInterface::getInstance().setLocalLoopbackInterface(&_audio);
|
AudioScriptingInterface::getInstance().setLocalAudioInterface(&_audio);
|
||||||
|
|
||||||
#ifdef HAVE_RTMIDI
|
#ifdef HAVE_RTMIDI
|
||||||
// setup the MIDIManager
|
// setup the MIDIManager
|
||||||
|
@ -454,23 +454,22 @@ Application::~Application() {
|
||||||
// ask the datagram processing thread to quit and wait until it is done
|
// ask the datagram processing thread to quit and wait until it is done
|
||||||
_nodeThread->quit();
|
_nodeThread->quit();
|
||||||
_nodeThread->wait();
|
_nodeThread->wait();
|
||||||
|
|
||||||
|
// kill any audio injectors that are still around
|
||||||
|
AudioScriptingInterface::getInstance().stopAllInjectors();
|
||||||
|
|
||||||
// stop the audio process
|
// stop the audio process
|
||||||
QMetaObject::invokeMethod(&_audio, "stop");
|
QMetaObject::invokeMethod(&_audio, "stop");
|
||||||
|
|
||||||
// ask the audio thread to quit and wait until it is done
|
// ask the audio thread to quit and wait until it is done
|
||||||
_audio.thread()->quit();
|
_audio.thread()->quit();
|
||||||
_audio.thread()->wait();
|
_audio.thread()->wait();
|
||||||
|
|
||||||
// kill any audio injectors that are still around
|
|
||||||
AudioScriptingInterface::getInstance().stopAllInjectors();
|
|
||||||
|
|
||||||
_octreeProcessor.terminate();
|
_octreeProcessor.terminate();
|
||||||
_voxelHideShowThread.terminate();
|
_voxelHideShowThread.terminate();
|
||||||
_voxelEditSender.terminate();
|
_voxelEditSender.terminate();
|
||||||
_entityEditSender.terminate();
|
_entityEditSender.terminate();
|
||||||
|
|
||||||
|
|
||||||
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
|
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
|
||||||
Menu::getInstance()->deleteLater();
|
Menu::getInstance()->deleteLater();
|
||||||
|
|
||||||
|
|
|
@ -32,19 +32,21 @@
|
||||||
#include <QtMultimedia/QAudioOutput>
|
#include <QtMultimedia/QAudioOutput>
|
||||||
#include <QSvgRenderer>
|
#include <QSvgRenderer>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <AudioInjector.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <StDev.h>
|
#include <StDev.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
#include "Audio.h"
|
|
||||||
|
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "PositionalAudioStream.h"
|
#include "PositionalAudioStream.h"
|
||||||
|
|
||||||
|
#include "Audio.h"
|
||||||
|
|
||||||
static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
|
static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
|
||||||
|
|
||||||
static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
||||||
|
@ -1366,24 +1368,34 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float
|
||||||
_drumSoundSample = 0;
|
_drumSoundSample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& injectorOptions) {
|
bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) {
|
||||||
if (audioByteArray.size() > 0) {
|
if (injector->getLocalBuffer()) {
|
||||||
QAudioFormat localFormat = _outputFormat;
|
QAudioFormat localFormat = _desiredOutputFormat;
|
||||||
|
localFormat.setChannelCount(isStereo ? 2 : 1);
|
||||||
|
|
||||||
if (!injectorOptions.isStereo()) {
|
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
|
||||||
localFormat.setChannelCount(1);
|
localFormat, this);
|
||||||
}
|
localOutput->setVolume(volume);
|
||||||
|
|
||||||
QAudioOutput* localSoundOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this);
|
// add this to our list of local injected outputs, we will need to clean it up when the injector says it is done
|
||||||
|
_injectedOutputInterfaces.insert(injector, localOutput);
|
||||||
|
|
||||||
QIODevice* localIODevice = localSoundOutput->start();
|
connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface);
|
||||||
if (localIODevice) {
|
|
||||||
localIODevice->write(audioByteArray);
|
localOutput->start(injector->getLocalBuffer());
|
||||||
} else {
|
return localOutput->state() == QAudio::ActiveState;
|
||||||
qDebug() << "Unable to handle audio byte array. Error:" << localSoundOutput->error();
|
}
|
||||||
}
|
|
||||||
} else {
|
return false;
|
||||||
qDebug() << "Audio::handleAudioByteArray called with an empty byte array. Sound is likely still downloading.";
|
}
|
||||||
|
|
||||||
|
void Audio::cleanupLocalOutputInterface() {
|
||||||
|
QAudioOutput* outputInterface = _injectedOutputInterfaces.value(sender());
|
||||||
|
if (outputInterface) {
|
||||||
|
qDebug() << "Stopping a QAudioOutput interface since injector" << sender() << "is finished";
|
||||||
|
|
||||||
|
outputInterface->stop();
|
||||||
|
outputInterface->deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ public slots:
|
||||||
void selectAudioFilterBassCut();
|
void selectAudioFilterBassCut();
|
||||||
void selectAudioFilterSmiley();
|
void selectAudioFilterSmiley();
|
||||||
|
|
||||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options);
|
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector);
|
||||||
|
|
||||||
void sendDownstreamAudioStatsPacket();
|
void sendDownstreamAudioStatsPacket();
|
||||||
|
|
||||||
|
@ -180,11 +180,11 @@ signals:
|
||||||
void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
||||||
void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void cleanupLocalOutputInterface();
|
||||||
private:
|
private:
|
||||||
void outputFormatChanged();
|
void outputFormatChanged();
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
QByteArray firstInputFrame;
|
QByteArray firstInputFrame;
|
||||||
QAudioInput* _audioInput;
|
QAudioInput* _audioInput;
|
||||||
QAudioFormat _desiredInputFormat;
|
QAudioFormat _desiredInputFormat;
|
||||||
|
@ -256,10 +256,6 @@ private:
|
||||||
float _iconColor;
|
float _iconColor;
|
||||||
qint64 _iconPulseTimeReference;
|
qint64 _iconPulseTimeReference;
|
||||||
|
|
||||||
/// Audio callback in class context.
|
|
||||||
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);
|
|
||||||
|
|
||||||
|
|
||||||
bool _processSpatialAudio; /// Process received audio by spatial audio hooks
|
bool _processSpatialAudio; /// Process received audio by spatial audio hooks
|
||||||
unsigned int _spatialAudioStart; /// Start of spatial audio interval (in sample rate time base)
|
unsigned int _spatialAudioStart; /// Start of spatial audio interval (in sample rate time base)
|
||||||
unsigned int _spatialAudioFinish; /// End of spatial audio interval (in sample rate time base)
|
unsigned int _spatialAudioFinish; /// End of spatial audio interval (in sample rate time base)
|
||||||
|
@ -372,6 +368,8 @@ private:
|
||||||
AudioOutputIODevice _audioOutputIODevice;
|
AudioOutputIODevice _audioOutputIODevice;
|
||||||
|
|
||||||
WeakRecorderPointer _recorder;
|
WeakRecorderPointer _recorder;
|
||||||
|
|
||||||
|
QHash<QObject*, QAudioOutput*> _injectedOutputInterfaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,13 @@
|
||||||
#define hifi_AbstractAudioInterface_h
|
#define hifi_AbstractAudioInterface_h
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
#include <QtMultimedia/qaudiooutput.h>
|
||||||
|
|
||||||
#include "AudioInjectorOptions.h"
|
#include "AudioInjectorOptions.h"
|
||||||
|
|
||||||
|
class AudioInjector;
|
||||||
|
class AudioInjectorLocalBuffer;
|
||||||
|
|
||||||
class AbstractAudioInterface : public QObject {
|
class AbstractAudioInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -24,7 +28,7 @@ public:
|
||||||
virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0;
|
virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0;
|
||||||
virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0;
|
virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0;
|
||||||
public slots:
|
public slots:
|
||||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options) = 0;
|
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AbstractAudioInterface*)
|
Q_DECLARE_METATYPE(AbstractAudioInterface*)
|
||||||
|
|
|
@ -21,6 +21,14 @@
|
||||||
|
|
||||||
#include "AudioInjector.h"
|
#include "AudioInjector.h"
|
||||||
|
|
||||||
|
QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) {
|
||||||
|
return engine->newQObject(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) {
|
||||||
|
out = qobject_cast<AudioInjector*>(object.toQObject());
|
||||||
|
}
|
||||||
|
|
||||||
AudioInjector::AudioInjector(QObject* parent) :
|
AudioInjector::AudioInjector(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_sound(NULL),
|
_sound(NULL),
|
||||||
|
@ -28,7 +36,8 @@ AudioInjector::AudioInjector(QObject* parent) :
|
||||||
_shouldStop(false),
|
_shouldStop(false),
|
||||||
_loudness(0.0f),
|
_loudness(0.0f),
|
||||||
_isFinished(false),
|
_isFinished(false),
|
||||||
_currentSendPosition(0)
|
_currentSendPosition(0),
|
||||||
|
_localBuffer(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +47,17 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO
|
||||||
_shouldStop(false),
|
_shouldStop(false),
|
||||||
_loudness(0.0f),
|
_loudness(0.0f),
|
||||||
_isFinished(false),
|
_isFinished(false),
|
||||||
_currentSendPosition(0)
|
_currentSendPosition(0),
|
||||||
|
_localBuffer(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioInjector::~AudioInjector() {
|
||||||
|
if (_localBuffer) {
|
||||||
|
_localBuffer->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioInjector::setOptions(AudioInjectorOptions& options) {
|
void AudioInjector::setOptions(AudioInjectorOptions& options) {
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
@ -50,9 +66,54 @@ float AudioInjector::getLoudness() {
|
||||||
return _loudness;
|
return _loudness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioInjector::injectAudio() {
|
||||||
|
if (_options.localOnly) {
|
||||||
|
injectLocally();
|
||||||
|
} else {
|
||||||
|
injectToMixer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioInjector::injectLocally() {
|
||||||
|
bool success = false;
|
||||||
|
if (_localAudioInterface) {
|
||||||
|
const QByteArray& soundByteArray = _sound->getByteArray();
|
||||||
|
|
||||||
|
if (soundByteArray.size() > 0) {
|
||||||
|
_localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this);
|
||||||
|
_localBuffer->open(QIODevice::ReadOnly);
|
||||||
|
_localBuffer->setShouldLoop(_options.loop);
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, success),
|
||||||
|
Q_ARG(bool, _options.stereo),
|
||||||
|
Q_ARG(qreal, _options.volume),
|
||||||
|
Q_ARG(AudioInjector*, this));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qDebug() << "AudioInjector::injectLocally cannot inject locally with no local audio interface present.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
// we never started so we are finished, call our stop method
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const uchar MAX_INJECTOR_VOLUME = 0xFF;
|
const uchar MAX_INJECTOR_VOLUME = 0xFF;
|
||||||
|
|
||||||
void AudioInjector::injectAudio() {
|
void AudioInjector::injectToMixer() {
|
||||||
QByteArray soundByteArray = _sound->getByteArray();
|
QByteArray soundByteArray = _sound->getByteArray();
|
||||||
|
|
||||||
if (_currentSendPosition < 0 ||
|
if (_currentSendPosition < 0 ||
|
||||||
|
@ -75,7 +136,7 @@ void AudioInjector::injectAudio() {
|
||||||
packetStream << QUuid::createUuid();
|
packetStream << QUuid::createUuid();
|
||||||
|
|
||||||
// pack the stereo/mono type of the stream
|
// pack the stereo/mono type of the stream
|
||||||
packetStream << _options.isStereo();
|
packetStream << _options.stereo;
|
||||||
|
|
||||||
// pack the flag for loopback
|
// pack the flag for loopback
|
||||||
uchar loopbackFlag = (uchar) true;
|
uchar loopbackFlag = (uchar) true;
|
||||||
|
@ -83,13 +144,13 @@ void AudioInjector::injectAudio() {
|
||||||
|
|
||||||
// pack the position for injected audio
|
// pack the position for injected audio
|
||||||
int positionOptionOffset = injectAudioPacket.size();
|
int positionOptionOffset = injectAudioPacket.size();
|
||||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()),
|
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.position),
|
||||||
sizeof(_options.getPosition()));
|
sizeof(_options.position));
|
||||||
|
|
||||||
// pack our orientation for injected audio
|
// pack our orientation for injected audio
|
||||||
int orientationOptionOffset = injectAudioPacket.size();
|
int orientationOptionOffset = injectAudioPacket.size();
|
||||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()),
|
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.orientation),
|
||||||
sizeof(_options.getOrientation()));
|
sizeof(_options.orientation));
|
||||||
|
|
||||||
// pack zero for radius
|
// pack zero for radius
|
||||||
float radius = 0;
|
float radius = 0;
|
||||||
|
@ -97,23 +158,23 @@ void AudioInjector::injectAudio() {
|
||||||
|
|
||||||
// pack 255 for attenuation byte
|
// pack 255 for attenuation byte
|
||||||
int volumeOptionOffset = injectAudioPacket.size();
|
int volumeOptionOffset = injectAudioPacket.size();
|
||||||
quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume();
|
quint8 volume = MAX_INJECTOR_VOLUME * _options.volume;
|
||||||
packetStream << volume;
|
packetStream << volume;
|
||||||
|
|
||||||
packetStream << _options.ignorePenumbra();
|
packetStream << _options.ignorePenumbra;
|
||||||
|
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
timer.start();
|
timer.start();
|
||||||
int nextFrame = 0;
|
int nextFrame = 0;
|
||||||
|
|
||||||
int numPreAudioDataBytes = injectAudioPacket.size();
|
int numPreAudioDataBytes = injectAudioPacket.size();
|
||||||
bool shouldLoop = _options.getLoop();
|
bool shouldLoop = _options.loop;
|
||||||
|
|
||||||
// loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks
|
// loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks
|
||||||
quint16 outgoingInjectedAudioSequenceNumber = 0;
|
quint16 outgoingInjectedAudioSequenceNumber = 0;
|
||||||
while (_currentSendPosition < soundByteArray.size() && !_shouldStop) {
|
while (_currentSendPosition < soundByteArray.size() && !_shouldStop) {
|
||||||
|
|
||||||
int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
|
int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
|
||||||
soundByteArray.size() - _currentSendPosition);
|
soundByteArray.size() - _currentSendPosition);
|
||||||
|
|
||||||
// Measure the loudness of this frame
|
// Measure the loudness of this frame
|
||||||
|
@ -125,12 +186,12 @@ void AudioInjector::injectAudio() {
|
||||||
_loudness /= (float)(bytesToCopy / sizeof(int16_t));
|
_loudness /= (float)(bytesToCopy / sizeof(int16_t));
|
||||||
|
|
||||||
memcpy(injectAudioPacket.data() + positionOptionOffset,
|
memcpy(injectAudioPacket.data() + positionOptionOffset,
|
||||||
&_options.getPosition(),
|
&_options.position,
|
||||||
sizeof(_options.getPosition()));
|
sizeof(_options.position));
|
||||||
memcpy(injectAudioPacket.data() + orientationOptionOffset,
|
memcpy(injectAudioPacket.data() + orientationOptionOffset,
|
||||||
&_options.getOrientation(),
|
&_options.orientation,
|
||||||
sizeof(_options.getOrientation()));
|
sizeof(_options.orientation));
|
||||||
volume = MAX_INJECTOR_VOLUME * _options.getVolume();
|
volume = MAX_INJECTOR_VOLUME * _options.volume;
|
||||||
memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume));
|
memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume));
|
||||||
|
|
||||||
// resize the QByteArray to the right size
|
// resize the QByteArray to the right size
|
||||||
|
@ -175,3 +236,13 @@ void AudioInjector::injectAudio() {
|
||||||
_isFinished = true;
|
_isFinished = true;
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioInjector::stop() {
|
||||||
|
_shouldStop = true;
|
||||||
|
|
||||||
|
if (_options.localOnly) {
|
||||||
|
// we're only a local injector, so we can say we are finished right away too
|
||||||
|
_isFinished = true;
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,20 +18,29 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
|
#include "AudioInjectorLocalBuffer.h"
|
||||||
#include "AudioInjectorOptions.h"
|
#include "AudioInjectorOptions.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
|
class AbstractAudioInterface;
|
||||||
|
|
||||||
class AudioInjector : public QObject {
|
class AudioInjector : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AudioInjector(QObject* parent);
|
AudioInjector(QObject* parent);
|
||||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||||
|
~AudioInjector();
|
||||||
|
|
||||||
bool isFinished() const { return _isFinished; }
|
bool isFinished() const { return _isFinished; }
|
||||||
int getCurrentSendPosition() const { return _currentSendPosition; }
|
int getCurrentSendPosition() const { return _currentSendPosition; }
|
||||||
|
|
||||||
|
AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; }
|
||||||
|
bool isLocalOnly() const { return _options.localOnly; }
|
||||||
|
|
||||||
|
void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
|
||||||
public slots:
|
public slots:
|
||||||
void injectAudio();
|
void injectAudio();
|
||||||
void stop() { _shouldStop = true; }
|
void stop();
|
||||||
void setOptions(AudioInjectorOptions& options);
|
void setOptions(AudioInjectorOptions& options);
|
||||||
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
||||||
float getLoudness();
|
float getLoudness();
|
||||||
|
@ -39,15 +48,22 @@ public slots:
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
private:
|
private:
|
||||||
|
void injectToMixer();
|
||||||
|
void injectLocally();
|
||||||
|
|
||||||
Sound* _sound;
|
Sound* _sound;
|
||||||
AudioInjectorOptions _options;
|
AudioInjectorOptions _options;
|
||||||
bool _shouldStop;
|
bool _shouldStop;
|
||||||
float _loudness;
|
float _loudness;
|
||||||
bool _isFinished;
|
bool _isFinished;
|
||||||
int _currentSendPosition;
|
int _currentSendPosition;
|
||||||
|
AbstractAudioInterface* _localAudioInterface;
|
||||||
|
AudioInjectorLocalBuffer* _localBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AudioInjector*)
|
Q_DECLARE_METATYPE(AudioInjector*)
|
||||||
|
|
||||||
|
QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in);
|
||||||
|
void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out);
|
||||||
|
|
||||||
#endif // hifi_AudioInjector_h
|
#endif // hifi_AudioInjector_h
|
||||||
|
|
74
libraries/audio/src/AudioInjectorLocalBuffer.cpp
Normal file
74
libraries/audio/src/AudioInjectorLocalBuffer.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//
|
||||||
|
// AudioInjectorLocalBuffer.cpp
|
||||||
|
// libraries/audio/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-11-11.
|
||||||
|
// 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 "AudioInjectorLocalBuffer.h"
|
||||||
|
|
||||||
|
AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) :
|
||||||
|
QIODevice(parent),
|
||||||
|
_rawAudioArray(rawAudioArray),
|
||||||
|
_shouldLoop(false),
|
||||||
|
_isStopped(false),
|
||||||
|
_currentOffset(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioInjectorLocalBuffer::stop() {
|
||||||
|
_isStopped = true;
|
||||||
|
QIODevice::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
|
||||||
|
if (!_isStopped) {
|
||||||
|
|
||||||
|
// first copy to the end of the raw audio
|
||||||
|
int bytesToEnd = _rawAudioArray.size() - _currentOffset;
|
||||||
|
|
||||||
|
int bytesRead = maxSize;
|
||||||
|
|
||||||
|
if (maxSize > bytesToEnd) {
|
||||||
|
bytesRead = bytesToEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data, _rawAudioArray.data() + _currentOffset, bytesRead);
|
||||||
|
|
||||||
|
// now check if we are supposed to loop and if we can copy more from the beginning
|
||||||
|
if (_shouldLoop && maxSize != bytesRead) {
|
||||||
|
bytesRead += recursiveReadFromFront(data + bytesRead, maxSize - bytesRead);
|
||||||
|
} else {
|
||||||
|
_currentOffset += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSize) {
|
||||||
|
// see how much we can get in this pass
|
||||||
|
int bytesRead = maxSize;
|
||||||
|
|
||||||
|
if (bytesRead > _rawAudioArray.size()) {
|
||||||
|
bytesRead = _rawAudioArray.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy that amount
|
||||||
|
memcpy(data, _rawAudioArray.data(), bytesRead);
|
||||||
|
|
||||||
|
// check if we need to call ourselves again and pull from the front again
|
||||||
|
if (bytesRead < maxSize) {
|
||||||
|
return bytesRead + recursiveReadFromFront(data, maxSize);
|
||||||
|
} else {
|
||||||
|
_currentOffset = bytesRead;
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
}
|
40
libraries/audio/src/AudioInjectorLocalBuffer.h
Normal file
40
libraries/audio/src/AudioInjectorLocalBuffer.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// AudioInjectorLocalBuffer.h
|
||||||
|
// libraries/audio/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-11-11.
|
||||||
|
// 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_AudioInjectorLocalBuffer_h
|
||||||
|
#define hifi_AudioInjectorLocalBuffer_h
|
||||||
|
|
||||||
|
#include <QtCore/qiodevice.h>
|
||||||
|
|
||||||
|
class AudioInjectorLocalBuffer : public QIODevice {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
qint64 readData(char* data, qint64 maxSize);
|
||||||
|
qint64 writeData(const char* data, qint64 maxSize) { return 0; }
|
||||||
|
|
||||||
|
void setShouldLoop(bool shouldLoop) { _shouldLoop = shouldLoop; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
qint64 recursiveReadFromFront(char* data, qint64 maxSize);
|
||||||
|
|
||||||
|
QByteArray _rawAudioArray;
|
||||||
|
bool _shouldLoop;
|
||||||
|
bool _isStopped;
|
||||||
|
|
||||||
|
int _currentOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AudioInjectorLocalBuffer_h
|
|
@ -9,33 +9,60 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <RegisteredMetaTypes.h>
|
||||||
|
|
||||||
#include "AudioInjectorOptions.h"
|
#include "AudioInjectorOptions.h"
|
||||||
|
|
||||||
AudioInjectorOptions::AudioInjectorOptions(QObject* parent) :
|
AudioInjectorOptions::AudioInjectorOptions() :
|
||||||
QObject(parent),
|
position(0.0f, 0.0f, 0.0f),
|
||||||
_position(0.0f, 0.0f, 0.0f),
|
volume(1.0f),
|
||||||
_volume(1.0f),
|
loop(false),
|
||||||
_loop(false),
|
orientation(glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||||
_orientation(glm::vec3(0.0f, 0.0f, 0.0f)),
|
stereo(false),
|
||||||
_isStereo(false),
|
ignorePenumbra(false),
|
||||||
_ignorePenumbra(false)
|
localOnly(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) {
|
QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions) {
|
||||||
_position = other._position;
|
QScriptValue obj = engine->newObject();
|
||||||
_volume = other._volume;
|
obj.setProperty("position", vec3toScriptValue(engine, injectorOptions.position));
|
||||||
_loop = other._loop;
|
obj.setProperty("volume", injectorOptions.volume);
|
||||||
_orientation = other._orientation;
|
obj.setProperty("loop", injectorOptions.loop);
|
||||||
_isStereo = other._isStereo;
|
obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation));
|
||||||
_ignorePenumbra = other._ignorePenumbra;
|
obj.setProperty("stereo", injectorOptions.stereo);
|
||||||
|
obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra);
|
||||||
|
obj.setProperty("localOnly", injectorOptions.localOnly);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) {
|
void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) {
|
||||||
_position = other._position;
|
if (object.property("position").isValid()) {
|
||||||
_volume = other._volume;
|
vec3FromScriptValue(object.property("position"), injectorOptions.position);
|
||||||
_loop = other._loop;
|
}
|
||||||
_orientation = other._orientation;
|
|
||||||
_isStereo = other._isStereo;
|
if (object.property("volume").isValid()) {
|
||||||
_ignorePenumbra = other._ignorePenumbra;
|
injectorOptions.volume = object.property("volume").toNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object.property("loop").isValid()) {
|
||||||
|
injectorOptions.loop = object.property("loop").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.property("orientation").isValid()) {
|
||||||
|
quatFromScriptValue(object.property("orientation"), injectorOptions.orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.property("stereo").isValid()) {
|
||||||
|
injectorOptions.stereo = object.property("stereo").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.property("ignorePenumbra").isValid()) {
|
||||||
|
injectorOptions.ignorePenumbra = object.property("ignorePenumbra").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.property("localOnly").isValid()) {
|
||||||
|
injectorOptions.localOnly = object.property("localOnly").toBool();
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,54 +12,26 @@
|
||||||
#ifndef hifi_AudioInjectorOptions_h
|
#ifndef hifi_AudioInjectorOptions_h
|
||||||
#define hifi_AudioInjectorOptions_h
|
#define hifi_AudioInjectorOptions_h
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtScript/qscriptengine.h>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
#include <RegisteredMetaTypes.h>
|
class AudioInjectorOptions {
|
||||||
|
|
||||||
class AudioInjectorOptions : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
|
||||||
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition)
|
|
||||||
Q_PROPERTY(float volume READ getVolume WRITE setVolume)
|
|
||||||
Q_PROPERTY(bool loop READ getLoop WRITE setLoop)
|
|
||||||
Q_PROPERTY(bool isStereo READ isStereo WRITE setIsStereo)
|
|
||||||
Q_PROPERTY(bool ignorePenumbra READ ignorePenumbra WRITE setIgnorePenumbra)
|
|
||||||
public:
|
public:
|
||||||
AudioInjectorOptions(QObject* parent = 0);
|
AudioInjectorOptions();
|
||||||
AudioInjectorOptions(const AudioInjectorOptions& other);
|
glm::vec3 position;
|
||||||
void operator=(const AudioInjectorOptions& other);
|
float volume;
|
||||||
|
bool loop;
|
||||||
const glm::vec3& getPosition() const { return _position; }
|
glm::quat orientation;
|
||||||
void setPosition(const glm::vec3& position) { _position = position; }
|
bool stereo;
|
||||||
|
bool ignorePenumbra;
|
||||||
float getVolume() const { return _volume; }
|
bool localOnly;
|
||||||
void setVolume(float volume) { _volume = volume; }
|
|
||||||
|
|
||||||
bool getLoop() const { return _loop; }
|
|
||||||
void setLoop(bool loop) { _loop = loop; }
|
|
||||||
|
|
||||||
const glm::quat& getOrientation() const { return _orientation; }
|
|
||||||
void setOrientation(const glm::quat& orientation) { _orientation = orientation; }
|
|
||||||
|
|
||||||
const bool isStereo() const { return _isStereo; }
|
|
||||||
void setIsStereo(const bool isStereo) { _isStereo = isStereo; }
|
|
||||||
|
|
||||||
const bool ignorePenumbra() const {return _ignorePenumbra; }
|
|
||||||
void setIgnorePenumbra(bool ignorePenumbra) { _ignorePenumbra = ignorePenumbra; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
glm::vec3 _position;
|
|
||||||
float _volume;
|
|
||||||
bool _loop;
|
|
||||||
glm::quat _orientation;
|
|
||||||
bool _isStereo;
|
|
||||||
bool _ignorePenumbra;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AudioInjectorOptions)
|
Q_DECLARE_METATYPE(AudioInjectorOptions);
|
||||||
|
|
||||||
|
QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions);
|
||||||
|
void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions);
|
||||||
|
|
||||||
#endif // hifi_AudioInjectorOptions_h
|
#endif // hifi_AudioInjectorOptions_h
|
||||||
|
|
|
@ -11,15 +11,20 @@
|
||||||
|
|
||||||
#include "AudioScriptingInterface.h"
|
#include "AudioScriptingInterface.h"
|
||||||
|
|
||||||
|
void registerAudioMetaTypes(QScriptEngine* engine) {
|
||||||
|
qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, soundToScriptValue, soundFromScriptValue);
|
||||||
|
}
|
||||||
|
|
||||||
AudioScriptingInterface& AudioScriptingInterface::getInstance() {
|
AudioScriptingInterface& AudioScriptingInterface::getInstance() {
|
||||||
static AudioScriptingInterface staticInstance;
|
static AudioScriptingInterface staticInstance;
|
||||||
return staticInstance;
|
return staticInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioScriptingInterface::AudioScriptingInterface() :
|
AudioScriptingInterface::AudioScriptingInterface() :
|
||||||
_localLoopbackInterface(NULL)
|
_localAudioInterface(NULL)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<AudioInjectorOptions>("AudioInjectorOptions");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioScriptingInterface::stopAllInjectors() {
|
void AudioScriptingInterface::stopAllInjectors() {
|
||||||
|
@ -37,24 +42,10 @@ void AudioScriptingInterface::stopAllInjectors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioScriptingInterface::playLocalSound(Sound* sound, const AudioInjectorOptions* injectorOptions) {
|
AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) {
|
||||||
if (sound->isStereo()) {
|
|
||||||
const_cast<AudioInjectorOptions*>(injectorOptions)->setIsStereo(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly
|
AudioInjector* injector = new AudioInjector(sound, injectorOptions);
|
||||||
QMetaObject::invokeMethod(_localLoopbackInterface, "handleAudioByteArray",
|
injector->setLocalAudioInterface(_localAudioInterface);
|
||||||
Qt::AutoConnection,
|
|
||||||
Q_ARG(QByteArray, sound->getByteArray()),
|
|
||||||
Q_ARG(const AudioInjectorOptions&, *injectorOptions));
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
QThread* injectorThread = new QThread();
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include "AudioInjector.h"
|
#include "AudioInjector.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS;
|
|
||||||
|
|
||||||
class AudioScriptingInterface : public QObject {
|
class AudioScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -27,13 +25,12 @@ public:
|
||||||
|
|
||||||
void stopAllInjectors();
|
void stopAllInjectors();
|
||||||
|
|
||||||
void setLocalLoopbackInterface(AbstractAudioInterface* audioInterface) { _localLoopbackInterface = audioInterface; }
|
void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; }
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
static float getLoudness(AudioInjector* injector);
|
static float getLoudness(AudioInjector* injector);
|
||||||
|
|
||||||
void playLocalSound(Sound *sound, const AudioInjectorOptions* injectorOptions = NULL);
|
AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||||
AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL);
|
|
||||||
|
|
||||||
void stopInjector(AudioInjector* injector);
|
void stopInjector(AudioInjector* injector);
|
||||||
bool isInjectorPlaying(AudioInjector* injector);
|
bool isInjectorPlaying(AudioInjector* injector);
|
||||||
|
@ -43,6 +40,9 @@ public slots:
|
||||||
private:
|
private:
|
||||||
AudioScriptingInterface();
|
AudioScriptingInterface();
|
||||||
QList< QPointer<AudioInjector> > _activeInjectors;
|
QList< QPointer<AudioInjector> > _activeInjectors;
|
||||||
AbstractAudioInterface* _localLoopbackInterface;
|
AbstractAudioInterface* _localAudioInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void registerAudioMetaTypes(QScriptEngine* engine);
|
||||||
|
|
||||||
#endif // hifi_AudioScriptingInterface_h
|
#endif // hifi_AudioScriptingInterface_h
|
||||||
|
|
|
@ -29,6 +29,15 @@
|
||||||
#include "AudioEditBuffer.h"
|
#include "AudioEditBuffer.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
|
|
||||||
|
QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in) {
|
||||||
|
return engine->newQObject(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundFromScriptValue(const QScriptValue& object, Sound*& out) {
|
||||||
|
out = qobject_cast<Sound*>(object.toQObject());
|
||||||
|
}
|
||||||
|
|
||||||
// procedural audio version of Sound
|
// procedural audio version of Sound
|
||||||
Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) :
|
Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
#include <QtScript/qscriptengine.h>
|
||||||
|
|
||||||
class Sound : public QObject {
|
class Sound : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -44,4 +45,9 @@ private slots:
|
||||||
void replyError(QNetworkReply::NetworkError code);
|
void replyError(QNetworkReply::NetworkError code);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Sound*)
|
||||||
|
|
||||||
|
QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in);
|
||||||
|
void soundFromScriptValue(const QScriptValue& object, Sound*& out);
|
||||||
|
|
||||||
#endif // hifi_Sound_h
|
#endif // hifi_Sound_h
|
||||||
|
|
|
@ -166,8 +166,8 @@ void Player::pausePlayer() {
|
||||||
|
|
||||||
void Player::setupAudioThread() {
|
void Player::setupAudioThread() {
|
||||||
_audioThread = new QThread();
|
_audioThread = new QThread();
|
||||||
_options.setPosition(_avatar->getPosition());
|
_options.position = _avatar->getPosition();
|
||||||
_options.setOrientation(_avatar->getOrientation());
|
_options.orientation = _avatar->getOrientation();
|
||||||
_injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater);
|
_injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater);
|
||||||
_injector->moveToThread(_audioThread);
|
_injector->moveToThread(_audioThread);
|
||||||
_audioThread->start();
|
_audioThread->start();
|
||||||
|
@ -292,8 +292,8 @@ void Player::play() {
|
||||||
qDebug() << "WARNING: Player couldn't find head data.";
|
qDebug() << "WARNING: Player couldn't find head data.";
|
||||||
}
|
}
|
||||||
|
|
||||||
_options.setPosition(_avatar->getPosition());
|
_options.position = _avatar->getPosition();
|
||||||
_options.setOrientation(_avatar->getOrientation());
|
_options.orientation = _avatar->getOrientation();
|
||||||
_injector->setOptions(_options);
|
_injector->setOptions(_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ void Player::setCurrentTime(int currentTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setVolume(float volume) {
|
void Player::setVolume(float volume) {
|
||||||
_options.setVolume(volume);
|
_options.volume = volume;
|
||||||
if (_injector) {
|
if (_injector) {
|
||||||
_injector->setOptions(_options);
|
_injector->setOptions(_options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,14 +74,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
|
||||||
out = qobject_cast<AvatarData*>(object.toQObject());
|
out = qobject_cast<AvatarData*>(object.toQObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) {
|
|
||||||
return engine->newQObject(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) {
|
|
||||||
out = qobject_cast<AudioInjector*>(object.toQObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
|
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) {
|
||||||
return engine->newQObject(in);
|
return engine->newQObject(in);
|
||||||
}
|
}
|
||||||
|
@ -234,7 +226,6 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*)
|
|
||||||
Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString)
|
Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString)
|
||||||
|
|
||||||
void ScriptEngine::init() {
|
void ScriptEngine::init() {
|
||||||
|
@ -254,6 +245,7 @@ void ScriptEngine::init() {
|
||||||
registerMenuItemProperties(this);
|
registerMenuItemProperties(this);
|
||||||
registerAnimationTypes(this);
|
registerAnimationTypes(this);
|
||||||
registerAvatarTypes(this);
|
registerAvatarTypes(this);
|
||||||
|
registerAudioMetaTypes(this);
|
||||||
Bitstream::registerTypes(this);
|
Bitstream::registerTypes(this);
|
||||||
|
|
||||||
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
|
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
|
||||||
|
@ -275,9 +267,6 @@ void ScriptEngine::init() {
|
||||||
QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
|
QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
|
||||||
globalObject().setProperty("Sound", soundMetaObject);
|
globalObject().setProperty("Sound", soundMetaObject);
|
||||||
|
|
||||||
QScriptValue injectionOptionValue = scriptValueFromQMetaObject<AudioInjectorOptions>();
|
|
||||||
globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
|
|
||||||
|
|
||||||
QScriptValue localVoxelsValue = scriptValueFromQMetaObject<LocalVoxels>();
|
QScriptValue localVoxelsValue = scriptValueFromQMetaObject<LocalVoxels>();
|
||||||
globalObject().setProperty("LocalVoxels", localVoxelsValue);
|
globalObject().setProperty("LocalVoxels", localVoxelsValue);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue