mirror of
https://github.com/overte-org/overte.git
synced 2025-04-26 01:56:22 +02:00
commit
faa370f797
25 changed files with 552 additions and 81 deletions
|
@ -37,7 +37,6 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
||||||
|
|
||||||
// FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now.
|
// FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now.
|
||||||
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||||
const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) * 1000;
|
|
||||||
|
|
||||||
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||||
ThreadedAssignment(message)
|
ThreadedAssignment(message)
|
||||||
|
|
46
interface/resources/icons/tablet-icons/scope-auto.svg
Normal file
46
interface/resources/icons/tablet-icons/scope-auto.svg
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M25.3,23.7c-0.6,0-1.2,0.2-1.6,0.7S23,25.4,23,26c0,0.6,0.2,1.1,0.7,1.6c0.5,0.5,1,0.7,1.6,0.7
|
||||||
|
c0.6,0,1.2-0.2,1.6-0.7c0.5-0.5,0.7-1,0.7-1.6c0-0.6-0.2-1.2-0.7-1.6C26.5,23.9,26,23.7,25.3,23.7z"/>
|
||||||
|
<path class="st0" d="M25.3,17.2c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21.2,30.3,17.2,25.3,17.2z M31.5,26c0,0.3-0.1,0.6-0.3,0.8
|
||||||
|
c-0.2,0.2-0.5,0.3-0.8,0.3c-0.2,0-0.3,0-0.5-0.1c-0.1,0-0.3,0-0.5-0.1c-0.2,0.6-0.3,1.1-0.6,1.4c0.2,0.1,0.3,0.2,0.4,0.3h0.1
|
||||||
|
c0.2,0.1,0.4,0.2,0.4,0.2c0.5,0.5,0.5,1.1,0,1.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0-0.6-0.1-0.8-0.3c0,0-0.1-0.2-0.2-0.4
|
||||||
|
c0,0,0-0.1-0.1-0.1c-0.1-0.1-0.2-0.2-0.2-0.4c-0.4,0.3-0.9,0.5-1.4,0.6c0.1,0.2,0.1,0.4,0.1,0.5c0.1,0.2,0.1,0.3,0.1,0.5
|
||||||
|
c0,0.3-0.1,0.6-0.3,0.8c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.5-0.3-0.8c0-0.2,0-0.3,0.1-0.5
|
||||||
|
c0-0.1,0-0.3,0.1-0.5c-0.5-0.1-1-0.3-1.4-0.6c-0.1,0.2-0.2,0.3-0.2,0.4L22.8,30c0,0.1-0.1,0.2-0.2,0.4c-0.2,0.2-0.5,0.3-0.8,0.3
|
||||||
|
c-0.3,0-0.6-0.1-0.8-0.3c-0.5-0.5-0.5-1.1,0-1.6c0.1-0.1,0.2-0.2,0.5-0.2c0-0.1,0.2-0.2,0.4-0.3c-0.2-0.3-0.4-0.8-0.6-1.4
|
||||||
|
C21.1,27,20.9,27,20.7,27V27c-0.1,0.1-0.2,0.1-0.5,0.1c-0.3,0-0.6-0.1-0.8-0.3c-0.2-0.2-0.3-0.5-0.3-0.8c0-0.3,0.1-0.6,0.3-0.8
|
||||||
|
c0.2-0.2,0.5-0.3,0.8-0.3c0.2,0,0.3,0,0.5,0.1c0.1,0,0.3,0,0.5,0.1c0.1-0.5,0.3-1,0.6-1.4c-0.1,0-0.2-0.1-0.4-0.2h-0.1
|
||||||
|
c-0.2-0.1-0.3-0.2-0.4-0.3c-0.5-0.5-0.5-1,0-1.5c0.5-0.5,1.1-0.5,1.6,0c0.1,0.1,0.2,0.2,0.2,0.4c0.1,0.1,0.2,0.2,0.3,0.5
|
||||||
|
c0.4-0.3,0.9-0.5,1.4-0.6c-0.1-0.2-0.1-0.3-0.1-0.5v-0.1c-0.1-0.2-0.1-0.3-0.1-0.5c0-0.3,0.1-0.6,0.3-0.8c0.2-0.2,0.5-0.3,0.8-0.3
|
||||||
|
c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.5,0.3,0.8c0,0.2,0,0.3-0.1,0.5v0.1c0,0.2,0,0.3-0.1,0.5c0.4,0.1,0.9,0.3,1.4,0.6
|
||||||
|
c0-0.2,0.1-0.3,0.2-0.5c0-0.1,0.1-0.2,0.3-0.4c0.2-0.2,0.4-0.3,0.8-0.3c0.3,0,0.6,0.1,0.8,0.3c0.5,0.5,0.5,1.1,0,1.6
|
||||||
|
c-0.2,0.2-0.3,0.2-0.4,0.3c-0.1,0.1-0.2,0.2-0.5,0.2c0.3,0.5,0.5,1,0.6,1.4c0.2-0.1,0.3-0.1,0.5-0.1H30c0.2-0.1,0.3-0.1,0.5-0.1
|
||||||
|
c0.3,0,0.6,0.1,0.8,0.3C31.4,25.5,31.5,25.7,31.5,26L31.5,26z"/>
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="6.9" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="5.1" height="3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4 KiB |
30
interface/resources/icons/tablet-icons/scope-pause.svg
Normal file
30
interface/resources/icons/tablet-icons/scope-pause.svg
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="5.3" height="3"/>
|
||||||
|
<path class="st0" d="M25.3,17c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21,30.3,17,25.3,17z M24.1,29.7c0,0.5-0.6,1-1.4,1
|
||||||
|
s-1.4-0.4-1.4-1v-7.3c0-0.5,0.6-1,1.4-1s1.4,0.4,1.4,1V29.7z M29.3,29.7c0,0.5-0.6,1-1.4,1c-0.8,0-1.4-0.4-1.4-1v-7.3
|
||||||
|
c0-0.5,0.6-1,1.4-1c0.8,0,1.4,0.4,1.4,1V29.7z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
30
interface/resources/icons/tablet-icons/scope-play.svg
Normal file
30
interface/resources/icons/tablet-icons/scope-play.svg
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M22.3,15.4v-2.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v3.5C20.7,15.9,21.5,15.6,22.3,15.4z"/>
|
||||||
|
<path class="st0" d="M25.3,15c0.4,0,0.8,0,1.1,0.1V8.6c0-0.6-0.5-1.2-1.2-1.2S24.1,8,24.1,8.6V15C24.5,15,24.9,15,25.3,15z"/>
|
||||||
|
<path class="st0" d="M30.6,16.3V3.6c0-0.6-0.5-1.2-1.2-1.2S28.3,3,28.3,3.6v11.7C29.1,15.6,29.9,15.9,30.6,16.3z"/>
|
||||||
|
<path class="st0" d="M48,24.9h-0.6v-2.1c0-0.6-0.5-1.2-1.2-1.2S45,22.2,45,22.9v2.1h-1.8V12c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2
|
||||||
|
v12.9H39v-9.6c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2V36c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-8.7h1.8v12.9
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V27.3H45v2.9c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.9H48c0.6,0,1.2-0.5,1.2-1.2
|
||||||
|
S48.6,24.9,48,24.9z"/>
|
||||||
|
<path class="st0" d="M13.9,12c0-0.6-0.5-1.2-1.2-1.2c-0.6,0-1.2,0.5-1.2,1.2v12.9H9.7v-4.6c0-0.6-0.5-1.2-1.2-1.2
|
||||||
|
c-0.6,0-1.2,0.5-1.2,1.2v4.6H5.5v-2.1c0-0.6-0.5-1.2-1.2-1.2s-1.2,0.5-1.2,1.2v2.1H2.6c-0.6,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2h0.6
|
||||||
|
v2.1c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-2.1h1.8v6.2c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2v-6.2h1.8v12.1
|
||||||
|
c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V12z"/>
|
||||||
|
<path class="st0" d="M28.3,37v9.8c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2V36.1C29.9,36.5,29.1,36.8,28.3,37z"/>
|
||||||
|
<path class="st0" d="M25.3,37.5c-0.4,0-0.8,0-1.2-0.1v4.5c0,0.6,0.5,1.2,1.2,1.2s1.2-0.5,1.2-1.2v-4.5
|
||||||
|
C26.1,37.4,25.7,37.5,25.3,37.5z"/>
|
||||||
|
<path class="st0" d="M19.9,36.1v3.3c0,0.6,0.5,1.2,1.2,1.2c0.6,0,1.2-0.5,1.2-1.2V37C21.5,36.8,20.7,36.5,19.9,36.1z"/>
|
||||||
|
<path class="st0" d="M25.3,17.2c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C34.4,21.2,30.3,17.2,25.3,17.2z M30.3,26.1l-6,5.4
|
||||||
|
c-0.1,0.1-0.2,0.1-0.4,0.1c-0.1,0-0.3,0-0.3-0.1c-0.3-0.1-0.5-0.4-0.5-0.5V20.9c0-0.1,0.2-0.4,0.4-0.5c0.1,0,0.2-0.1,0.3-0.1
|
||||||
|
c0.2,0,0.3,0,0.4,0.1l6,4.8c0.1,0.1,0.2,0.3,0.2,0.4C30.5,25.8,30.4,26,30.3,26.1z"/>
|
||||||
|
<rect x="12" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
<rect x="32.9" y="24.6" class="st0" width="7.3" height="3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -181,6 +181,31 @@ Item {
|
||||||
root.avatarMixerOutPps + "pps, " +
|
root.avatarMixerOutPps + "pps, " +
|
||||||
root.myAvatarSendRate.toFixed(2) + "hz";
|
root.myAvatarSendRate.toFixed(2) + "hz";
|
||||||
}
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Mixer In: " + root.audioMixerInKbps + " kbps, " +
|
||||||
|
root.audioMixerInPps + "pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio In Audio: " + root.audioAudioInboundPPS + " pps, " +
|
||||||
|
"Silent: " + root.audioSilentInboundPPS + " pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Mixer Out: " + root.audioMixerOutKbps + " kbps, " +
|
||||||
|
root.audioMixerOutPps + "pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Out Mic: " + root.audioMicOutboundPPS + " pps, " +
|
||||||
|
"Silent: " + root.audioSilentOutboundPPS + " pps";
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "Audio Codec: " + root.audioCodec + " Noise Gate: " +
|
||||||
|
root.audioNoiseGate;
|
||||||
|
}
|
||||||
StatText {
|
StatText {
|
||||||
visible: root.expanded;
|
visible: root.expanded;
|
||||||
text: "Downloads: " + root.downloads + "/" + root.downloadLimit +
|
text: "Downloads: " + root.downloads + "/" + root.downloadLimit +
|
||||||
|
|
|
@ -1188,6 +1188,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
// set the local loopback interface for local sounds
|
// set the local loopback interface for local sounds
|
||||||
AudioInjector::setLocalAudioInterface(audioIO.data());
|
AudioInjector::setLocalAudioInterface(audioIO.data());
|
||||||
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
|
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
|
||||||
|
connect(audioIO.data(), &AudioClient::noiseGateOpened, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateOpened);
|
||||||
|
connect(audioIO.data(), &AudioClient::noiseGateClosed, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::noiseGateClosed);
|
||||||
|
connect(audioIO.data(), &AudioClient::inputReceived, &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::inputReceived);
|
||||||
|
|
||||||
|
|
||||||
this->installEventFilter(this);
|
this->installEventFilter(this);
|
||||||
|
|
||||||
|
@ -1950,6 +1954,8 @@ void Application::initializeUi() {
|
||||||
rootContext->setContextProperty("ApplicationInterface", this);
|
rootContext->setContextProperty("ApplicationInterface", this);
|
||||||
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
||||||
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||||
|
rootContext->setContextProperty("AudioScope", DependencyManager::get<AudioScope>().data());
|
||||||
|
|
||||||
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||||
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||||
_fileDownload = new FileScriptingInterface(engine);
|
_fileDownload = new FileScriptingInterface(engine);
|
||||||
|
@ -3178,7 +3184,23 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mouseDoublePressEvent(QMouseEvent* event) const {
|
void Application::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
auto eventPosition = getApplicationCompositor().getMouseEventPosition(event);
|
||||||
|
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||||
|
QMouseEvent mappedEvent(event->type(),
|
||||||
|
transformedPos,
|
||||||
|
event->screenPos(), event->button(),
|
||||||
|
event->buttons(), event->modifiers());
|
||||||
|
|
||||||
|
if (!_aboutToQuit) {
|
||||||
|
getOverlays().mouseDoublePressEvent(&mappedEvent);
|
||||||
|
if (!_controllerScriptingInterface->areEntityClicksCaptured()) {
|
||||||
|
getEntities()->mouseDoublePressEvent(&mappedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
|
@ -5525,6 +5547,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||||
|
scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get<AudioScope>().data());
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||||
|
|
|
@ -497,7 +497,7 @@ private:
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
void mouseDoublePressEvent(QMouseEvent* event) const;
|
void mouseDoublePressEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
|
||||||
void touchBeginEvent(QTouchEvent* event);
|
void touchBeginEvent(QTouchEvent* event);
|
||||||
|
|
|
@ -52,12 +52,14 @@ AudioScope::AudioScope() :
|
||||||
connect(audioIO.data(), &AudioClient::inputReceived, this, &AudioScope::addInputToScope);
|
connect(audioIO.data(), &AudioClient::inputReceived, this, &AudioScope::addInputToScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioScope::toggle() {
|
void AudioScope::setVisible(bool visible) {
|
||||||
_isEnabled = !_isEnabled;
|
if (_isEnabled != visible) {
|
||||||
if (_isEnabled) {
|
_isEnabled = visible;
|
||||||
allocateScope();
|
if (_isEnabled) {
|
||||||
} else {
|
allocateScope();
|
||||||
freeScope();
|
} else {
|
||||||
|
freeScope();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,14 @@ public:
|
||||||
void render(RenderArgs* renderArgs, int width, int height);
|
void render(RenderArgs* renderArgs, int width, int height);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void toggle();
|
void toggle() { setVisible(!_isEnabled); }
|
||||||
|
void setVisible(bool visible);
|
||||||
|
bool getVisible() const { return _isEnabled; }
|
||||||
|
|
||||||
void togglePause() { _isPaused = !_isPaused; }
|
void togglePause() { _isPaused = !_isPaused; }
|
||||||
|
void setPause(bool paused) { _isPaused = paused; }
|
||||||
|
bool getPause() { return _isPaused; }
|
||||||
|
|
||||||
void selectAudioScopeFiveFrames();
|
void selectAudioScopeFiveFrames();
|
||||||
void selectAudioScopeTwentyFrames();
|
void selectAudioScopeTwentyFrames();
|
||||||
void selectAudioScopeFiftyFrames();
|
void selectAudioScopeFiftyFrames();
|
||||||
|
@ -74,7 +80,6 @@ private:
|
||||||
int _inputID;
|
int _inputID;
|
||||||
int _outputLeftID;
|
int _outputLeftID;
|
||||||
int _outputRightD;
|
int _outputRightD;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AudioScope_h
|
#endif // hifi_AudioScope_h
|
||||||
|
|
|
@ -198,15 +198,16 @@ void Stats::updateStats(bool force) {
|
||||||
STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
|
STAT_UPDATE(avatarMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
|
||||||
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
|
||||||
} else {
|
} else {
|
||||||
STAT_UPDATE(avatarMixerInKbps, -1);
|
STAT_UPDATE(avatarMixerInKbps, -1);
|
||||||
STAT_UPDATE(avatarMixerInPps, -1);
|
STAT_UPDATE(avatarMixerInPps, -1);
|
||||||
STAT_UPDATE(avatarMixerOutKbps, -1);
|
STAT_UPDATE(avatarMixerOutKbps, -1);
|
||||||
STAT_UPDATE(avatarMixerOutPps, -1);
|
STAT_UPDATE(avatarMixerOutPps, -1);
|
||||||
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
|
||||||
}
|
}
|
||||||
|
STAT_UPDATE(myAvatarSendRate, avatarManager->getMyAvatarSendRate());
|
||||||
|
|
||||||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||||
|
auto audioClient = DependencyManager::get<AudioClient>();
|
||||||
if (audioMixerNode || force) {
|
if (audioMixerNode || force) {
|
||||||
STAT_UPDATE(audioMixerKbps, roundf(
|
STAT_UPDATE(audioMixerKbps, roundf(
|
||||||
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
||||||
|
@ -214,10 +215,30 @@ void Stats::updateStats(bool force) {
|
||||||
STAT_UPDATE(audioMixerPps, roundf(
|
STAT_UPDATE(audioMixerPps, roundf(
|
||||||
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
||||||
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
|
||||||
|
STAT_UPDATE(audioMixerInKbps, roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||||
|
STAT_UPDATE(audioMicOutboundPPS, audioClient->getMicAudioOutboundPPS());
|
||||||
|
STAT_UPDATE(audioSilentOutboundPPS, audioClient->getSilentOutboundPPS());
|
||||||
|
STAT_UPDATE(audioAudioInboundPPS, audioClient->getAudioInboundPPS());
|
||||||
|
STAT_UPDATE(audioSilentInboundPPS, audioClient->getSilentInboundPPS());
|
||||||
} else {
|
} else {
|
||||||
STAT_UPDATE(audioMixerKbps, -1);
|
STAT_UPDATE(audioMixerKbps, -1);
|
||||||
STAT_UPDATE(audioMixerPps, -1);
|
STAT_UPDATE(audioMixerPps, -1);
|
||||||
|
STAT_UPDATE(audioMixerInKbps, -1);
|
||||||
|
STAT_UPDATE(audioMixerInPps, -1);
|
||||||
|
STAT_UPDATE(audioMixerOutKbps, -1);
|
||||||
|
STAT_UPDATE(audioMixerOutPps, -1);
|
||||||
|
STAT_UPDATE(audioMicOutboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioSilentOutboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioAudioInboundPPS, -1);
|
||||||
|
STAT_UPDATE(audioSilentInboundPPS, -1);
|
||||||
}
|
}
|
||||||
|
STAT_UPDATE(audioCodec, audioClient->getSelectedAudioFormat());
|
||||||
|
STAT_UPDATE(audioNoiseGate, audioClient->getNoiseGateOpen() ? "Open" : "Closed");
|
||||||
|
|
||||||
|
|
||||||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||||
STAT_UPDATE(downloads, loadingRequests.size());
|
STAT_UPDATE(downloads, loadingRequests.size());
|
||||||
|
|
|
@ -70,8 +70,20 @@ class Stats : public QQuickItem {
|
||||||
STATS_PROPERTY(int, avatarMixerOutKbps, 0)
|
STATS_PROPERTY(int, avatarMixerOutKbps, 0)
|
||||||
STATS_PROPERTY(int, avatarMixerOutPps, 0)
|
STATS_PROPERTY(int, avatarMixerOutPps, 0)
|
||||||
STATS_PROPERTY(float, myAvatarSendRate, 0)
|
STATS_PROPERTY(float, myAvatarSendRate, 0)
|
||||||
|
|
||||||
|
STATS_PROPERTY(int, audioMixerInKbps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerInPps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerOutKbps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMixerOutPps, 0)
|
||||||
STATS_PROPERTY(int, audioMixerKbps, 0)
|
STATS_PROPERTY(int, audioMixerKbps, 0)
|
||||||
STATS_PROPERTY(int, audioMixerPps, 0)
|
STATS_PROPERTY(int, audioMixerPps, 0)
|
||||||
|
STATS_PROPERTY(int, audioMicOutboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioSilentOutboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioAudioInboundPPS, 0)
|
||||||
|
STATS_PROPERTY(int, audioSilentInboundPPS, 0)
|
||||||
|
STATS_PROPERTY(QString, audioCodec, QString())
|
||||||
|
STATS_PROPERTY(QString, audioNoiseGate, QString())
|
||||||
|
|
||||||
STATS_PROPERTY(int, downloads, 0)
|
STATS_PROPERTY(int, downloads, 0)
|
||||||
STATS_PROPERTY(int, downloadLimit, 0)
|
STATS_PROPERTY(int, downloadLimit, 0)
|
||||||
STATS_PROPERTY(int, downloadsPending, 0)
|
STATS_PROPERTY(int, downloadsPending, 0)
|
||||||
|
@ -180,8 +192,19 @@ signals:
|
||||||
void avatarMixerOutKbpsChanged();
|
void avatarMixerOutKbpsChanged();
|
||||||
void avatarMixerOutPpsChanged();
|
void avatarMixerOutPpsChanged();
|
||||||
void myAvatarSendRateChanged();
|
void myAvatarSendRateChanged();
|
||||||
|
void audioMixerInKbpsChanged();
|
||||||
|
void audioMixerInPpsChanged();
|
||||||
|
void audioMixerOutKbpsChanged();
|
||||||
|
void audioMixerOutPpsChanged();
|
||||||
void audioMixerKbpsChanged();
|
void audioMixerKbpsChanged();
|
||||||
void audioMixerPpsChanged();
|
void audioMixerPpsChanged();
|
||||||
|
void audioMicOutboundPPSChanged();
|
||||||
|
void audioSilentOutboundPPSChanged();
|
||||||
|
void audioAudioInboundPPSChanged();
|
||||||
|
void audioSilentInboundPPSChanged();
|
||||||
|
void audioCodecChanged();
|
||||||
|
void audioNoiseGateChanged();
|
||||||
|
|
||||||
void downloadsChanged();
|
void downloadsChanged();
|
||||||
void downloadLimitChanged();
|
void downloadLimitChanged();
|
||||||
void downloadsPendingChanged();
|
void downloadsPendingChanged();
|
||||||
|
|
|
@ -768,6 +768,26 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||||
|
|
||||||
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
|
// Only Web overlays can have focus.
|
||||||
|
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentClickingOnOverlayID));
|
||||||
|
if (thisOverlay) {
|
||||||
|
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
||||||
|
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit mouseDoublePressOffOverlay();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ public:
|
||||||
OverlayID addOverlay(Overlay::Pointer overlay);
|
OverlayID addOverlay(Overlay::Pointer overlay);
|
||||||
|
|
||||||
bool mousePressEvent(QMouseEvent* event);
|
bool mousePressEvent(QMouseEvent* event);
|
||||||
|
bool mouseDoublePressEvent(QMouseEvent* event);
|
||||||
bool mouseReleaseEvent(QMouseEvent* event);
|
bool mouseReleaseEvent(QMouseEvent* event);
|
||||||
bool mouseMoveEvent(QMouseEvent* event);
|
bool mouseMoveEvent(QMouseEvent* event);
|
||||||
|
|
||||||
|
@ -300,9 +301,11 @@ signals:
|
||||||
void panelDeleted(OverlayID id);
|
void panelDeleted(OverlayID id);
|
||||||
|
|
||||||
void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
|
void mouseDoublePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void mouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void mousePressOffOverlay();
|
void mousePressOffOverlay();
|
||||||
|
void mouseDoublePressOffOverlay();
|
||||||
|
|
||||||
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event);
|
void hoverEnterOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event);
|
void hoverOverOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
|
|
|
@ -608,6 +608,13 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
|
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||||
|
_silentInbound.increment();
|
||||||
|
} else {
|
||||||
|
_audioInbound.increment();
|
||||||
|
}
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||||
|
|
||||||
|
@ -1021,9 +1028,10 @@ void AudioClient::handleAudioInput() {
|
||||||
// if we performed the noise gate we can get values from it instead of enumerating the samples again
|
// if we performed the noise gate we can get values from it instead of enumerating the samples again
|
||||||
_lastInputLoudness = _inputGate.getLastLoudness();
|
_lastInputLoudness = _inputGate.getLastLoudness();
|
||||||
|
|
||||||
if (_inputGate.clippedInLastFrame()) {
|
if (_inputGate.clippedInLastBlock()) {
|
||||||
_timeSinceLastClip = 0.0f;
|
_timeSinceLastClip = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
float loudness = 0.0f;
|
float loudness = 0.0f;
|
||||||
|
|
||||||
|
@ -1041,6 +1049,12 @@ void AudioClient::handleAudioInput() {
|
||||||
|
|
||||||
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
|
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
|
||||||
|
|
||||||
|
if (_inputGate.openedInLastBlock()) {
|
||||||
|
emit noiseGateOpened();
|
||||||
|
} else if (_inputGate.closedInLastBlock()) {
|
||||||
|
emit noiseGateClosed();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// our input loudness is 0, since we're muted
|
// our input loudness is 0, since we're muted
|
||||||
_lastInputLoudness = 0;
|
_lastInputLoudness = 0;
|
||||||
|
@ -1057,9 +1071,13 @@ void AudioClient::handleAudioInput() {
|
||||||
// the output from the input gate (eventually, this could be crossfaded)
|
// the output from the input gate (eventually, this could be crossfaded)
|
||||||
// and allow the codec to properly encode down to silent/zero. If we still
|
// and allow the codec to properly encode down to silent/zero. If we still
|
||||||
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
|
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
|
||||||
if (_lastInputLoudness == 0 && !_inputGate.closedInLastFrame()) {
|
if (_lastInputLoudness == 0 && !_inputGate.closedInLastBlock()) {
|
||||||
packetType = PacketType::SilentAudioFrame;
|
packetType = PacketType::SilentAudioFrame;
|
||||||
|
_silentOutbound.increment();
|
||||||
|
} else {
|
||||||
|
_micAudioOutbound.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform audioTransform;
|
Transform audioTransform;
|
||||||
audioTransform.setTranslation(_positionGetter());
|
audioTransform.setTranslation(_positionGetter());
|
||||||
audioTransform.setRotation(_orientationGetter());
|
audioTransform.setRotation(_orientationGetter());
|
||||||
|
@ -1084,6 +1102,7 @@ void AudioClient::handleAudioInput() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME - should this go through the noise gate and honor mute and echo?
|
||||||
void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
||||||
Transform audioTransform;
|
Transform audioTransform;
|
||||||
audioTransform.setTranslation(_positionGetter());
|
audioTransform.setTranslation(_positionGetter());
|
||||||
|
@ -1096,6 +1115,8 @@ void AudioClient::handleRecordedAudioInput(const QByteArray& audio) {
|
||||||
encodedBuffer = audio;
|
encodedBuffer = audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_micAudioOutbound.increment();
|
||||||
|
|
||||||
// FIXME check a flag to see if we should echo audio?
|
// FIXME check a flag to see if we should echo audio?
|
||||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber,
|
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber,
|
||||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include <AudioLimiter.h>
|
#include <AudioLimiter.h>
|
||||||
#include <AudioConstants.h>
|
#include <AudioConstants.h>
|
||||||
|
|
||||||
|
#include <shared/RateCounter.h>
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
#include "AudioIOStats.h"
|
#include "AudioIOStats.h"
|
||||||
|
@ -121,6 +123,13 @@ public:
|
||||||
void negotiateAudioFormat();
|
void negotiateAudioFormat();
|
||||||
void selectAudioFormat(const QString& selectedCodecName);
|
void selectAudioFormat(const QString& selectedCodecName);
|
||||||
|
|
||||||
|
Q_INVOKABLE QString getSelectedAudioFormat() const { return _selectedCodecName; }
|
||||||
|
Q_INVOKABLE bool getNoiseGateOpen() const { return _inputGate.isOpen(); }
|
||||||
|
Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); }
|
||||||
|
Q_INVOKABLE float getMicAudioOutboundPPS() const { return _micAudioOutbound.rate(); }
|
||||||
|
Q_INVOKABLE float getSilentInboundPPS() const { return _silentInbound.rate(); }
|
||||||
|
Q_INVOKABLE float getAudioInboundPPS() const { return _audioInbound.rate(); }
|
||||||
|
|
||||||
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
||||||
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
||||||
|
|
||||||
|
@ -218,6 +227,8 @@ signals:
|
||||||
void inputReceived(const QByteArray& inputSamples);
|
void inputReceived(const QByteArray& inputSamples);
|
||||||
void outputBytesToNetwork(int numBytes);
|
void outputBytesToNetwork(int numBytes);
|
||||||
void inputBytesFromNetwork(int numBytes);
|
void inputBytesFromNetwork(int numBytes);
|
||||||
|
void noiseGateOpened();
|
||||||
|
void noiseGateClosed();
|
||||||
|
|
||||||
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
||||||
void deviceChanged();
|
void deviceChanged();
|
||||||
|
@ -382,6 +393,11 @@ private:
|
||||||
Encoder* _encoder { nullptr }; // for outbound mic stream
|
Encoder* _encoder { nullptr }; // for outbound mic stream
|
||||||
|
|
||||||
QThread* _checkDevicesThread { nullptr };
|
QThread* _checkDevicesThread { nullptr };
|
||||||
|
|
||||||
|
RateCounter<> _silentOutbound;
|
||||||
|
RateCounter<> _micAudioOutbound;
|
||||||
|
RateCounter<> _silentInbound;
|
||||||
|
RateCounter<> _audioInbound;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,16 @@
|
||||||
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
||||||
|
|
||||||
AudioNoiseGate::AudioNoiseGate() :
|
AudioNoiseGate::AudioNoiseGate() :
|
||||||
_inputFrameCounter(0),
|
_inputBlockCounter(0),
|
||||||
_lastLoudness(0.0f),
|
_lastLoudness(0.0f),
|
||||||
_quietestFrame(std::numeric_limits<float>::max()),
|
_quietestBlock(std::numeric_limits<float>::max()),
|
||||||
_loudestFrame(0.0f),
|
_loudestBlock(0.0f),
|
||||||
_didClipInLastFrame(false),
|
_didClipInLastBlock(false),
|
||||||
_dcOffset(0.0f),
|
_dcOffset(0.0f),
|
||||||
_measuredFloor(0.0f),
|
_measuredFloor(0.0f),
|
||||||
_sampleCounter(0),
|
_sampleCounter(0),
|
||||||
_isOpen(false),
|
_isOpen(false),
|
||||||
_framesToClose(0)
|
_blocksToClose(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||||
//
|
//
|
||||||
// DC Offset correction
|
// DC Offset correction
|
||||||
//
|
//
|
||||||
// Measure the DC offset over a trailing number of frames, and remove it from the input signal.
|
// Measure the DC offset over a trailing number of blocks, and remove it from the input signal.
|
||||||
// This causes the noise background measurements and server muting to be more accurate. Many off-board
|
// This causes the noise background measurements and server muting to be more accurate. Many off-board
|
||||||
// ADC's have a noticeable DC offset.
|
// ADC's have a noticeable DC offset.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +51,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||||
// Update measured DC offset
|
// Update measured DC offset
|
||||||
measuredDcOffset /= numSamples;
|
measuredDcOffset /= numSamples;
|
||||||
if (_dcOffset == 0.0f) {
|
if (_dcOffset == 0.0f) {
|
||||||
// On first frame, copy over measured offset
|
// On first block, copy over measured offset
|
||||||
_dcOffset = measuredDcOffset;
|
_dcOffset = measuredDcOffset;
|
||||||
} else {
|
} else {
|
||||||
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
||||||
|
@ -69,13 +69,13 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
//
|
//
|
||||||
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
|
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
|
||||||
// Make this value lower for more sensitivity and less rejection of noise.
|
// Make this value lower for more sensitivity and less rejection of noise.
|
||||||
// NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded
|
// NOISE_GATE_WIDTH: The number of samples in an audio block for which the height must be exceeded
|
||||||
// to open the gate.
|
// to open the gate.
|
||||||
// NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames
|
// NOISE_GATE_CLOSE_BLOCK_DELAY: Once the noise is below the gate height for the block, how many blocks
|
||||||
// will we wait before closing the gate.
|
// will we wait before closing the gate.
|
||||||
// NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor.
|
// NOISE_GATE_BLOCKS_TO_AVERAGE: How many audio blocks should we average together to compute noise floor.
|
||||||
// More means better rejection but also can reject continuous things like singing.
|
// More means better rejection but also can reject continuous things like singing.
|
||||||
// NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor?
|
// NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor?
|
||||||
|
|
||||||
float loudness = 0;
|
float loudness = 0;
|
||||||
int thisSample = 0;
|
int thisSample = 0;
|
||||||
|
@ -83,16 +83,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
const float NOISE_GATE_HEIGHT = 7.0f;
|
const float NOISE_GATE_HEIGHT = 7.0f;
|
||||||
const int NOISE_GATE_WIDTH = 5;
|
const int NOISE_GATE_WIDTH = 5;
|
||||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
|
||||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
const int NOISE_GATE_BLOCKS_TO_AVERAGE = 5;
|
||||||
|
|
||||||
// Check clipping, and check if should open noise gate
|
// Check clipping, and check if should open noise gate
|
||||||
_didClipInLastFrame = false;
|
_didClipInLastBlock = false;
|
||||||
|
|
||||||
for (int i = 0; i < numSamples; i++) {
|
for (int i = 0; i < numSamples; i++) {
|
||||||
thisSample = std::abs(samples[i]);
|
thisSample = std::abs(samples[i]);
|
||||||
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
||||||
_didClipInLastFrame = true;
|
_didClipInLastBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
loudness += thisSample;
|
loudness += thisSample;
|
||||||
|
@ -104,54 +104,81 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
_lastLoudness = fabs(loudness / numSamples);
|
_lastLoudness = fabs(loudness / numSamples);
|
||||||
|
|
||||||
if (_quietestFrame > _lastLoudness) {
|
if (_quietestBlock > _lastLoudness) {
|
||||||
_quietestFrame = _lastLoudness;
|
_quietestBlock = _lastLoudness;
|
||||||
}
|
}
|
||||||
if (_loudestFrame < _lastLoudness) {
|
if (_loudestBlock < _lastLoudness) {
|
||||||
_loudestFrame = _lastLoudness;
|
_loudestBlock = _lastLoudness;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
||||||
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
||||||
_quietestFrame = std::numeric_limits<float>::max();
|
_quietestBlock = std::numeric_limits<float>::max();
|
||||||
_loudestFrame = 0.0f;
|
_loudestBlock = 0.0f;
|
||||||
_inputFrameCounter = 0;
|
_inputBlockCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Noise Gate is enabled, check and turn the gate on and off
|
// If Noise Gate is enabled, check and turn the gate on and off
|
||||||
float averageOfAllSampleFrames = 0.0f;
|
float averageOfAllSampleBlocks = 0.0f;
|
||||||
_sampleFrames[_sampleCounter++] = _lastLoudness;
|
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
||||||
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
|
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_BLOCKS) {
|
||||||
float smallestSample = std::numeric_limits<float>::max();
|
float smallestSample = std::numeric_limits<float>::max();
|
||||||
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) {
|
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_BLOCKS - NOISE_GATE_BLOCKS_TO_AVERAGE; i += NOISE_GATE_BLOCKS_TO_AVERAGE) {
|
||||||
float thisAverage = 0.0f;
|
float thisAverage = 0.0f;
|
||||||
for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) {
|
for (int j = i; j < i + NOISE_GATE_BLOCKS_TO_AVERAGE; j++) {
|
||||||
thisAverage += _sampleFrames[j];
|
thisAverage += _sampleBlocks[j];
|
||||||
averageOfAllSampleFrames += _sampleFrames[j];
|
averageOfAllSampleBlocks += _sampleBlocks[j];
|
||||||
}
|
}
|
||||||
thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE;
|
thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
|
||||||
|
|
||||||
if (thisAverage < smallestSample) {
|
if (thisAverage < smallestSample) {
|
||||||
smallestSample = thisAverage;
|
smallestSample = thisAverage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES;
|
averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
|
||||||
_measuredFloor = smallestSample;
|
_measuredFloor = smallestSample;
|
||||||
_sampleCounter = 0;
|
_sampleCounter = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_closedInLastBlock = false;
|
||||||
|
_openedInLastBlock = false;
|
||||||
|
|
||||||
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
||||||
|
_openedInLastBlock = !_isOpen;
|
||||||
_isOpen = true;
|
_isOpen = true;
|
||||||
_framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY;
|
_blocksToClose = NOISE_GATE_CLOSE_BLOCK_DELAY;
|
||||||
} else {
|
} else {
|
||||||
if (--_framesToClose == 0) {
|
if (--_blocksToClose == 0) {
|
||||||
_closedInLastFrame = !_isOpen;
|
_closedInLastBlock = _isOpen;
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_isOpen) {
|
if (!_isOpen) {
|
||||||
memset(samples, 0, numSamples * sizeof(int16_t));
|
// First block after being closed gets faded to silence, we fade across
|
||||||
|
// the entire block on fading out. All subsequent blocks are muted by being slammed
|
||||||
|
// to zeros
|
||||||
|
if (_closedInLastBlock) {
|
||||||
|
float fadeSlope = (1.0f / numSamples);
|
||||||
|
for (int i = 0; i < numSamples; i++) {
|
||||||
|
float fadedSample = (1.0f - ((float)i * fadeSlope)) * (float)samples[i];
|
||||||
|
samples[i] = (int16_t)fadedSample;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset(samples, 0, numSamples * sizeof(int16_t));
|
||||||
|
}
|
||||||
_lastLoudness = 0;
|
_lastLoudness = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_openedInLastBlock) {
|
||||||
|
// would be nice to do a little crossfade from silence, but we only want to fade
|
||||||
|
// across the first 1/10th of the block, because we don't want to miss early
|
||||||
|
// transients.
|
||||||
|
int fadeSamples = numSamples / 10; // fade over 1/10th of the samples
|
||||||
|
float fadeSlope = (1.0f / fadeSamples);
|
||||||
|
for (int i = 0; i < fadeSamples; i++) {
|
||||||
|
float fadedSample = (float)i * fadeSlope * (float)samples[i];
|
||||||
|
samples[i] = (int16_t)fadedSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
|
||||||
|
|
||||||
class AudioNoiseGate {
|
class AudioNoiseGate {
|
||||||
public:
|
public:
|
||||||
|
@ -23,26 +23,29 @@ public:
|
||||||
void gateSamples(int16_t* samples, int numSamples);
|
void gateSamples(int16_t* samples, int numSamples);
|
||||||
void removeDCOffset(int16_t* samples, int numSamples);
|
void removeDCOffset(int16_t* samples, int numSamples);
|
||||||
|
|
||||||
bool clippedInLastFrame() const { return _didClipInLastFrame; }
|
bool clippedInLastBlock() const { return _didClipInLastBlock; }
|
||||||
bool closedInLastFrame() const { return _closedInLastFrame; }
|
bool closedInLastBlock() const { return _closedInLastBlock; }
|
||||||
|
bool openedInLastBlock() const { return _openedInLastBlock; }
|
||||||
|
bool isOpen() const { return _isOpen; }
|
||||||
float getMeasuredFloor() const { return _measuredFloor; }
|
float getMeasuredFloor() const { return _measuredFloor; }
|
||||||
float getLastLoudness() const { return _lastLoudness; }
|
float getLastLoudness() const { return _lastLoudness; }
|
||||||
|
|
||||||
static const float CLIPPING_THRESHOLD;
|
static const float CLIPPING_THRESHOLD;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _inputFrameCounter;
|
int _inputBlockCounter;
|
||||||
float _lastLoudness;
|
float _lastLoudness;
|
||||||
float _quietestFrame;
|
float _quietestBlock;
|
||||||
float _loudestFrame;
|
float _loudestBlock;
|
||||||
bool _didClipInLastFrame;
|
bool _didClipInLastBlock;
|
||||||
float _dcOffset;
|
float _dcOffset;
|
||||||
float _measuredFloor;
|
float _measuredFloor;
|
||||||
float _sampleFrames[NUMBER_OF_NOISE_SAMPLE_FRAMES];
|
float _sampleBlocks[NUMBER_OF_NOISE_SAMPLE_BLOCKS];
|
||||||
int _sampleCounter;
|
int _sampleCounter;
|
||||||
bool _isOpen;
|
bool _isOpen;
|
||||||
bool _closedInLastFrame { false };
|
bool _closedInLastBlock { false };
|
||||||
int _framesToClose;
|
bool _openedInLastBlock { false };
|
||||||
|
int _blocksToClose;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AudioNoiseGate_h
|
#endif // hifi_AudioNoiseGate_h
|
|
@ -736,6 +736,52 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
|
// If we don't have a tree, or we're in the process of shutting down, then don't
|
||||||
|
// process these events.
|
||||||
|
if (!_tree || _shuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent");
|
||||||
|
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||||
|
|
||||||
|
bool precisionPicking = !_dontDoPrecisionPicking;
|
||||||
|
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
|
||||||
|
if (rayPickResult.intersects) {
|
||||||
|
//qCDebug(entitiesrenderer) << "mouseDoublePressEvent over entity:" << rayPickResult.entityID;
|
||||||
|
|
||||||
|
QString urlString = rayPickResult.properties.getHref();
|
||||||
|
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||||
|
if (url.isValid() && !url.isEmpty()){
|
||||||
|
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||||
|
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
|
||||||
|
pos2D, rayPickResult.intersection,
|
||||||
|
rayPickResult.surfaceNormal, ray.direction,
|
||||||
|
toPointerButton(*event), toPointerButtons(*event));
|
||||||
|
|
||||||
|
emit mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
|
||||||
|
|
||||||
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseDoublePressOnEntity", pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||||
|
emit clickDownOnEntity(_currentClickingOnEntityID, pointerEvent);
|
||||||
|
if (_entitiesScriptEngine) {
|
||||||
|
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "doubleclickOnEntity", pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastPointerEvent = pointerEvent;
|
||||||
|
_lastPointerEventValid = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
emit mouseDoublePressOffEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
// If we don't have a tree, or we're in the process of shutting down, then don't
|
// If we don't have a tree, or we're in the process of shutting down, then don't
|
||||||
// process these events.
|
// process these events.
|
||||||
|
|
|
@ -90,6 +90,7 @@ public:
|
||||||
// event handles which may generate entity related events
|
// event handles which may generate entity related events
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseDoublePressEvent(QMouseEvent* event);
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
|
||||||
/// connect our signals to anEntityScriptingInterface for firing of events related clicking,
|
/// connect our signals to anEntityScriptingInterface for firing of events related clicking,
|
||||||
|
@ -103,9 +104,11 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
void mouseDoublePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mouseMoveOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void mousePressOffEntity();
|
void mousePressOffEntity();
|
||||||
|
void mouseDoublePressOffEntity();
|
||||||
|
|
||||||
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
|
|
@ -32,10 +32,13 @@ protected:
|
||||||
Q_INVOKABLE void setStereoInput(bool stereo);
|
Q_INVOKABLE void setStereoInput(bool stereo);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mutedByMixer();
|
void mutedByMixer(); /// the client has been muted by the mixer
|
||||||
void environmentMuted();
|
void environmentMuted(); /// the entire environment has been muted by the mixer
|
||||||
void receivedFirstPacket();
|
void receivedFirstPacket(); /// the client has received its first packet from the audio mixer
|
||||||
void disconnected();
|
void disconnected(); /// the client has been disconnected from the audio mixer
|
||||||
|
void noiseGateOpened(); /// the noise gate has opened
|
||||||
|
void noiseGateClosed(); /// the noise gate has closed
|
||||||
|
void inputReceived(const QByteArray& inputSamples); /// a frame of mic input audio has been received and processed
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioScriptingInterface();
|
AudioScriptingInterface();
|
||||||
|
|
|
@ -48,6 +48,9 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
|
||||||
case Press:
|
case Press:
|
||||||
obj.setProperty("type", "Press");
|
obj.setProperty("type", "Press");
|
||||||
break;
|
break;
|
||||||
|
case DoublePress:
|
||||||
|
obj.setProperty("type", "DoublePress");
|
||||||
|
break;
|
||||||
case Release:
|
case Release:
|
||||||
obj.setProperty("type", "Release");
|
obj.setProperty("type", "Release");
|
||||||
break;
|
break;
|
||||||
|
@ -131,6 +134,8 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
|
||||||
QString typeStr = type.isString() ? type.toString() : "Move";
|
QString typeStr = type.isString() ? type.toString() : "Move";
|
||||||
if (typeStr == "Press") {
|
if (typeStr == "Press") {
|
||||||
event._type = Press;
|
event._type = Press;
|
||||||
|
} else if (typeStr == "DoublePress") {
|
||||||
|
event._type = DoublePress;
|
||||||
} else if (typeStr == "Release") {
|
} else if (typeStr == "Release") {
|
||||||
event._type = Release;
|
event._type = Release;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,9 +28,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventType {
|
enum EventType {
|
||||||
Press, // A button has just been pressed
|
Press, // A button has just been pressed
|
||||||
Release, // A button has just been released
|
DoublePress, // A button has just been double pressed
|
||||||
Move // The pointer has just moved
|
Release, // A button has just been released
|
||||||
|
Move // The pointer has just moved
|
||||||
};
|
};
|
||||||
|
|
||||||
PointerEvent();
|
PointerEvent();
|
||||||
|
|
|
@ -24,29 +24,34 @@ public:
|
||||||
RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor
|
RateCounter() { _rate = 0; } // avoid use of std::atomic copy ctor
|
||||||
|
|
||||||
void increment(size_t count = 1) {
|
void increment(size_t count = 1) {
|
||||||
auto now = usecTimestampNow();
|
checkRate();
|
||||||
float currentIntervalMs = (now - _start) / (float) USECS_PER_MSEC;
|
|
||||||
if (currentIntervalMs > (float) INTERVAL) {
|
|
||||||
float currentCount = _count;
|
|
||||||
float intervalSeconds = currentIntervalMs / (float) MSECS_PER_SECOND;
|
|
||||||
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
|
|
||||||
_start = now;
|
|
||||||
_count = 0;
|
|
||||||
};
|
|
||||||
_count += count;
|
_count += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rate() const { return _rate; }
|
float rate() const { checkRate(); return _rate; }
|
||||||
|
|
||||||
uint8_t precision() const { return PRECISION; }
|
uint8_t precision() const { return PRECISION; }
|
||||||
|
|
||||||
uint32_t interval() const { return INTERVAL; }
|
uint32_t interval() const { return INTERVAL; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t _start { usecTimestampNow() };
|
mutable uint64_t _start { usecTimestampNow() };
|
||||||
size_t _count { 0 };
|
mutable size_t _count { 0 };
|
||||||
const float _scale { powf(10, PRECISION) };
|
const float _scale { powf(10, PRECISION) };
|
||||||
std::atomic<float> _rate;
|
mutable std::atomic<float> _rate;
|
||||||
|
|
||||||
|
void checkRate() const {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
float currentIntervalMs = (now - _start) / (float)USECS_PER_MSEC;
|
||||||
|
if (currentIntervalMs > (float)INTERVAL) {
|
||||||
|
float currentCount = _count;
|
||||||
|
float intervalSeconds = currentIntervalMs / (float)MSECS_PER_SECOND;
|
||||||
|
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
|
||||||
|
_start = now;
|
||||||
|
_count = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
19
script-archive/entityScripts/doubleClickExample.js
Normal file
19
script-archive/entityScripts/doubleClickExample.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
(function() {
|
||||||
|
var _this;
|
||||||
|
function DoubleClickExample() {
|
||||||
|
_this = this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleClickExample.prototype = {
|
||||||
|
clickDownOnEntity: function() {
|
||||||
|
print("clickDownOnEntity");
|
||||||
|
},
|
||||||
|
|
||||||
|
doubleclickOnEntity: function() {
|
||||||
|
print("doubleclickOnEntity");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return new DoubleClickExample();
|
||||||
|
});
|
95
scripts/system/audioScope.js
Normal file
95
scripts/system/audioScope.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
"use strict";
|
||||||
|
//
|
||||||
|
// audioScope.js
|
||||||
|
// scripts/system/
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 3/10/2016
|
||||||
|
// Copyright 2016 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
|
||||||
|
//
|
||||||
|
/* global Script, Tablet, AudioScope, Audio */
|
||||||
|
|
||||||
|
(function () { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
var scopeVisibile = AudioScope.getVisible();
|
||||||
|
var scopePaused = AudioScope.getPause();
|
||||||
|
var autoPause = false;
|
||||||
|
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var showScopeButton = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/scope.svg",
|
||||||
|
text: "Audio Scope",
|
||||||
|
isActive: scopeVisibile
|
||||||
|
});
|
||||||
|
|
||||||
|
var scopePauseImage = "icons/tablet-icons/scope-pause.svg";
|
||||||
|
var scopePlayImage = "icons/tablet-icons/scope-play.svg";
|
||||||
|
|
||||||
|
var pauseScopeButton = tablet.addButton({
|
||||||
|
icon: scopePaused ? scopePlayImage : scopePauseImage,
|
||||||
|
text: scopePaused ? "Unpause" : "Pause",
|
||||||
|
isActive: scopePaused
|
||||||
|
});
|
||||||
|
|
||||||
|
var autoPauseScopeButton = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/scope-auto.svg",
|
||||||
|
text: "Auto Pause",
|
||||||
|
isActive: autoPause
|
||||||
|
});
|
||||||
|
|
||||||
|
function setScopePause(paused) {
|
||||||
|
scopePaused = paused;
|
||||||
|
pauseScopeButton.editProperties({
|
||||||
|
isActive: scopePaused,
|
||||||
|
icon: scopePaused ? scopePlayImage : scopePauseImage,
|
||||||
|
text: scopePaused ? "Unpause" : "Pause"
|
||||||
|
});
|
||||||
|
AudioScope.setPause(scopePaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
showScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
scopeVisibile = !scopeVisibile;
|
||||||
|
showScopeButton.editProperties({
|
||||||
|
isActive: scopeVisibile
|
||||||
|
});
|
||||||
|
|
||||||
|
AudioScope.setVisible(scopeVisibile);
|
||||||
|
});
|
||||||
|
|
||||||
|
pauseScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
setScopePause(!scopePaused);
|
||||||
|
});
|
||||||
|
|
||||||
|
autoPauseScopeButton.clicked.connect(function () {
|
||||||
|
// toggle button active state
|
||||||
|
autoPause = !autoPause;
|
||||||
|
autoPauseScopeButton.editProperties({
|
||||||
|
isActive: autoPause,
|
||||||
|
text: autoPause ? "Auto Pause" : "Manual"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
tablet.removeButton(showScopeButton);
|
||||||
|
tablet.removeButton(pauseScopeButton);
|
||||||
|
tablet.removeButton(autoPauseScopeButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
Audio.noiseGateOpened.connect(function(){
|
||||||
|
if (autoPause) {
|
||||||
|
setScopePause(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Audio.noiseGateClosed.connect(function(){
|
||||||
|
// noise gate closed
|
||||||
|
if (autoPause) {
|
||||||
|
setScopePause(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}()); // END LOCAL_SCOPE
|
Loading…
Reference in a new issue