first commit
This commit is contained in:
commit
5e720d2995
BIN
Locales/ja_JP.qm
Normal file
BIN
Locales/ja_JP.qm
Normal file
Binary file not shown.
BIN
Locales/zh.qm
Normal file
BIN
Locales/zh.qm
Normal file
Binary file not shown.
BIN
Locales/zh_CN.qm
Normal file
BIN
Locales/zh_CN.qm
Normal file
Binary file not shown.
4
Presets/Circle/preset.json
Normal file
4
Presets/Circle/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://advp.widget.mashiros.top/widget",
|
||||
"settings": "settings.xml"
|
||||
}
|
||||
BIN
Presets/Circle/preview.png
Normal file
BIN
Presets/Circle/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
8
Presets/Circle/settings.xml
Normal file
8
Presets/Circle/settings.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Center Line":true,"Center Color":"#ff4500","Line Color":"#ff4500","Line Position":0,"Data Length":0,"Channel":2,"Reverse":false,"Rotate Settings":{"Center Enable":false,"Center Angle":10,"Line Enable":false,"Line Angle":10},"Data Settings":{"Auto Normalizing":true,"Amplitude":4,"Unit Style":0}}</value>
|
||||
<value name="styles">{"index":2}</value>
|
||||
<value name="current_style">"nvg://advp.widget.mashiros.top/advp-style-preset-circle#Style.qml"</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_waves#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Line Width":1,"Line Color":"#ff4500","Data Settings":{"Auto Normalizing":true,"Amplitude":10}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-circle#Style.qml">{"__version":"1.0.0","__cfg_height":740,"Main Color":"#ff4500","Line Position":0,"Line Width":1,"Max Range":50,"Data Length":0,"Channel":2,"Reverse":false,"Rotate":false,"Ratate Speed":10,"Angle":0,"Data Settings":{"Auto Normalizing":true,"Amplitude":10,"Unit Style":0}}</value>
|
||||
</map>
|
||||
4
Presets/Line/preset.json
Normal file
4
Presets/Line/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://advp.widget.mashiros.top/widget",
|
||||
"settings": "settings.xml"
|
||||
}
|
||||
BIN
Presets/Line/preview.png
Normal file
BIN
Presets/Line/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
6
Presets/Line/settings.xml
Normal file
6
Presets/Line/settings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Center Line":true,"Center Color":"#ff4500","Line Color":"#ff4500","Line Position":0,"Data Length":0,"Channel":2,"Reverse":false,"Rotate Settings":{"Center Enable":false,"Center Angle":10,"Line Enable":false,"Line Angle":10},"Data Settings":{"Auto Normalizing":true,"Amplitude":4,"Unit Style":0}}</value>
|
||||
<value name="styles">{"index":0}</value>
|
||||
<value name="current_style">"nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml"</value>
|
||||
</map>
|
||||
4
Presets/Ordinal_Scale_UI_bottom/preset.json
Normal file
4
Presets/Ordinal_Scale_UI_bottom/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://advp.widget.mashiros.top/widget",
|
||||
"settings": "settings.xml"
|
||||
}
|
||||
BIN
Presets/Ordinal_Scale_UI_bottom/preview.png
Normal file
BIN
Presets/Ordinal_Scale_UI_bottom/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
10
Presets/Ordinal_Scale_UI_bottom/settings.xml
Normal file
10
Presets/Ordinal_Scale_UI_bottom/settings.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Center Line":true,"Center Color":"#ff4500","Line Color":"#ff4500","Line Position":0,"Data Length":0,"Channel":2,"Reverse":false,"Rotate Settings":{"Center Enable":false,"Center Angle":10,"Line Enable":false,"Line Angle":10},"Data Settings":{"Auto Normalizing":true,"Amplitude":4,"Unit Style":0}}</value>
|
||||
<value name="styles">{"index":4}</value>
|
||||
<value name="current_style">"nvg://advp.widget.mashiros.top/advp-style-preset-ordinal_scale_ui_bottom#Style.qml"</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_waves#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Line Width":1,"Line Color":"#ff4500","Data Settings":{"Auto Normalizing":true,"Amplitude":10}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-circle#Style.qml">{"__version":"1.0.0","__cfg_height":740,"Main Color":"#ff4500","Line Position":0,"Line Width":1,"Max Range":50,"Data Length":0,"Channel":2,"Reverse":false,"Rotate":false,"Ratate Speed":10,"Angle":0,"Data Settings":{"Auto Normalizing":true,"Amplitude":10,"Unit Style":0}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-solidcircle#Style.qml">{"__version":"1.0.0","__cfg_height":740,"Main Color":"#ff4500","Line Position":0,"Line Width":1,"Max Range":50,"Data Length":0,"Channel":2,"Reverse":false,"Rotate":false,"Ratate Speed":10,"Angle":0,"Data Settings":{"Auto Normalizing":true,"Amplitude":10,"Unit Style":0}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-ordinal_scale_ui_bottom#Style.qml">{"__version":"1.0.0","__cfg_height":710,"Bass Color":"#dc143c","Alto Color":"#f8f8ff","Treble Color":"#4169e1","Bass AM":100,"Alto AM":150,"Treble AM":200,"Static AM":15,"Speed":20,"Data Settings":{"Auto Normalizing":true,"Amplitude":10}}</value>
|
||||
</map>
|
||||
4
Presets/Solidcircle/preset.json
Normal file
4
Presets/Solidcircle/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://advp.widget.mashiros.top/widget",
|
||||
"settings": "settings.xml"
|
||||
}
|
||||
BIN
Presets/Solidcircle/preview.png
Normal file
BIN
Presets/Solidcircle/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
9
Presets/Solidcircle/settings.xml
Normal file
9
Presets/Solidcircle/settings.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Center Line":true,"Center Color":"#ff4500","Line Color":"#ff4500","Line Position":0,"Data Length":0,"Channel":2,"Reverse":false,"Rotate Settings":{"Center Enable":false,"Center Angle":10,"Line Enable":false,"Line Angle":10},"Data Settings":{"Auto Normalizing":true,"Amplitude":4,"Unit Style":0}}</value>
|
||||
<value name="styles">{"index":3}</value>
|
||||
<value name="current_style">"nvg://advp.widget.mashiros.top/advp-style-preset-solidcircle#Style.qml"</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_waves#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Line Width":1,"Line Color":"#ff4500","Data Settings":{"Auto Normalizing":true,"Amplitude":10}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-circle#Style.qml">{"__version":"1.0.0","__cfg_height":740,"Main Color":"#ff4500","Line Position":0,"Line Width":1,"Max Range":50,"Data Length":0,"Channel":2,"Reverse":false,"Rotate":false,"Ratate Speed":10,"Angle":0,"Data Settings":{"Auto Normalizing":true,"Amplitude":10,"Unit Style":0}}</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset-solidcircle#Style.qml">{"__version":"1.0.0","__cfg_height":740,"Main Color":"#ff4500","Line Position":0,"Line Width":1,"Max Range":50,"Data Length":0,"Channel":2,"Reverse":false,"Rotate":false,"Ratate Speed":10,"Angle":0,"Data Settings":{"Auto Normalizing":true,"Amplitude":10,"Unit Style":0}}</value>
|
||||
</map>
|
||||
4
Presets/Waves/preset.json
Normal file
4
Presets/Waves/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://advp.widget.mashiros.top/widget",
|
||||
"settings": "settings.xml"
|
||||
}
|
||||
BIN
Presets/Waves/preview.png
Normal file
BIN
Presets/Waves/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
7
Presets/Waves/settings.xml
Normal file
7
Presets/Waves/settings.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_line#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Center Line":true,"Center Color":"#ff4500","Line Color":"#ff4500","Line Position":0,"Data Length":0,"Channel":2,"Reverse":false,"Rotate Settings":{"Center Enable":false,"Center Angle":10,"Line Enable":false,"Line Angle":10},"Data Settings":{"Auto Normalizing":true,"Amplitude":4,"Unit Style":0}}</value>
|
||||
<value name="styles">{"index":1}</value>
|
||||
<value name="current_style">"nvg://advp.widget.mashiros.top/advp-style-preset_waves#Style.qml"</value>
|
||||
<value name="nvg://advp.widget.mashiros.top/advp-style-preset_waves#Style.qml">{"__version":"1.0.0","__cfg_height":580,"Line Width":1,"Line Color":"#ff4500","Data Settings":{"Auto Normalizing":true,"Amplitude":10}}</value>
|
||||
</map>
|
||||
BIN
bin/ADVServer.exe
Normal file
BIN
bin/ADVServer.exe
Normal file
Binary file not shown.
13
bin/advConfig.ini
Normal file
13
bin/advConfig.ini
Normal file
@ -0,0 +1,13 @@
|
||||
[Server]
|
||||
ip = local
|
||||
port = 5055
|
||||
maxClient = 10
|
||||
logger = true
|
||||
|
||||
[FFT]
|
||||
attack = 5
|
||||
decay = 5
|
||||
norspeed = 1
|
||||
peakthr = 10
|
||||
fps = 35
|
||||
changeSpeed = 20
|
||||
23
module.qml
Normal file
23
module.qml
Normal file
@ -0,0 +1,23 @@
|
||||
import NERvGear 1.0 as NVG
|
||||
import NERvGear.Private 1.0 as NVGP
|
||||
|
||||
import "./qml"
|
||||
|
||||
NVG.Module {
|
||||
initialize: function () {
|
||||
console.log("Initializing ADV-Plugin.");
|
||||
Common.execute("../bin/ADVServer.exe", "-reboot");
|
||||
Common.setWsocket(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
ready: function () {
|
||||
console.log("ADV-Plugin is ready.");
|
||||
}
|
||||
|
||||
cleanup: function () {
|
||||
console.log("Cleaning up ADV-Plugin.");
|
||||
Common.setWsocket(false);
|
||||
Common.execute("../bin/ADVServer.exe", "-close");
|
||||
}
|
||||
}
|
||||
144
package.json
Normal file
144
package.json
Normal file
@ -0,0 +1,144 @@
|
||||
{
|
||||
"name": "top.mashiros.widget.advp",
|
||||
"version": "1.0.0",
|
||||
|
||||
"title": {
|
||||
"en": "ADV Plugin",
|
||||
"zh": "音頻可視化插件",
|
||||
"zh_CN": "音频可视化插件",
|
||||
"ja_JP": "音声視覚化プラグイン"
|
||||
},
|
||||
|
||||
"description": {
|
||||
"en": "Audio visualization plugin for SAO Utils",
|
||||
"zh": "用于SAO Utils 的音頻可視化插件",
|
||||
"zh_CN": "用于SAO Utils的音频可视化插件",
|
||||
"ja_JP": "SAO Utils用の音声視覚化プラグイン"
|
||||
},
|
||||
|
||||
"homepage": "https://nvg.dev/Mashiro_Sorata/ADV-Plugin",
|
||||
|
||||
"bugs": {
|
||||
"email": "mashiro_sorata@qq.com",
|
||||
"url": "https://nvg.dev/Mashiro_Sorata/ADV-Plugin/issues"
|
||||
},
|
||||
|
||||
"author": {
|
||||
"name": "Mashiro_Sorata",
|
||||
"email": "mashiro_sorata@qq.com",
|
||||
"url": "https://www.mashiros.top/"
|
||||
},
|
||||
|
||||
"engines": {
|
||||
"qt": "~5",
|
||||
"qt.quick": ">=2.12",
|
||||
"nvg.api": "~1"
|
||||
},
|
||||
|
||||
"main": "module.qml",
|
||||
|
||||
"resources": [
|
||||
{
|
||||
"location": "/widget",
|
||||
"catalog": "widget",
|
||||
"title": {
|
||||
"en": "ADV Widget",
|
||||
"zh": "音頻可視化挂件",
|
||||
"zh_CN": "音频可视化挂件",
|
||||
"ja_JP": "音声視覚化プラグイン"
|
||||
},
|
||||
"preview": "preview.png",
|
||||
"entry": "qml/Main.qml"
|
||||
},
|
||||
{
|
||||
"location": "/advp-style-preset_line",
|
||||
"catalog": "top.mashiros.advp-style",
|
||||
"title": "Preset Line",
|
||||
"entry": "./styles/Preset_line"
|
||||
},
|
||||
{
|
||||
"location": "/advp-style-preset_waves",
|
||||
"catalog": "top.mashiros.advp-style",
|
||||
"title": "Preset Waves",
|
||||
"entry": "./styles/Preset_waves"
|
||||
},
|
||||
{
|
||||
"location": "/advp-style-preset-circle",
|
||||
"catalog": "top.mashiros.advp-style",
|
||||
"title": "Preset Circle",
|
||||
"entry": "./styles/Preset_circle"
|
||||
},
|
||||
{
|
||||
"location": "/advp-style-preset-solidcircle",
|
||||
"catalog": "top.mashiros.advp-style",
|
||||
"title": "Preset Solid-circle",
|
||||
"entry": "./styles/Preset_solidcircle"
|
||||
},
|
||||
{
|
||||
"location": "/advp-style-preset-ordinal_scale_ui_bottom",
|
||||
"catalog": "top.mashiros.advp-style",
|
||||
"title": "Preset Ordinal Scale UI bottom",
|
||||
"entry": "./styles/Preset_Ordinal_Scale_UI_bottom"
|
||||
},
|
||||
{
|
||||
"location": "/preset/advp-style-preset_line",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "ADV Preset Line",
|
||||
"zh": "ADV預置 Line",
|
||||
"zh_CN": "ADV预置 Line",
|
||||
"ja_JP": "ADVプリセット Line"
|
||||
},
|
||||
"preview": "Presets/Line/preview.png",
|
||||
"entry": "Presets/Line/preset.json"
|
||||
},
|
||||
{
|
||||
"location": "/preset/advp-style-preset_waves",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "ADV Preset Waves",
|
||||
"zh": "ADV預置 Waves",
|
||||
"zh_CN": "ADV预置 Waves",
|
||||
"ja_JP": "ADVプリセット Waves"
|
||||
},
|
||||
"preview": "Presets/Waves/preview.png",
|
||||
"entry": "Presets/Waves/preset.json"
|
||||
},
|
||||
{
|
||||
"location": "/preset/advp-style-preset_circle",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "ADV Preset Circle",
|
||||
"zh": "ADV預置 Circle",
|
||||
"zh_CN": "ADV预置 Circle",
|
||||
"ja_JP": "ADVプリセット Circle"
|
||||
},
|
||||
"preview": "Presets/Circle/preview.png",
|
||||
"entry": "Presets/Circle/preset.json"
|
||||
},
|
||||
{
|
||||
"location": "/preset/advp-style-preset_solidcircle",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "ADV Preset Solid-circle",
|
||||
"zh": "ADV預置 Solid-circle",
|
||||
"zh_CN": "ADV预置 Solid-circle",
|
||||
"ja_JP": "ADVプリセット Solid-circle"
|
||||
},
|
||||
"preview": "Presets/Solidcircle/preview.png",
|
||||
"entry": "Presets/Solidcircle/preset.json"
|
||||
},
|
||||
{
|
||||
"location": "/preset/advp-style-preset_ordinal_scale_ui_bottom",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "ADV Preset Ordinal Scale UI bottom",
|
||||
"zh": "ADV預置 序列之爭底部UI",
|
||||
"zh_CN": "ADV预置 序列之争底部UI",
|
||||
"ja_JP": "ADVプリセット オーディナル・スケール- UI 下部"
|
||||
},
|
||||
"preview": "Presets/Ordinal_Scale_UI_bottom/preview.png",
|
||||
"entry": "Presets/Ordinal_Scale_UI_bottom/preset.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
preview.png
Normal file
BIN
preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
133
qml/Common.qml
Normal file
133
qml/Common.qml
Normal file
@ -0,0 +1,133 @@
|
||||
pragma Singleton
|
||||
import QtQml 2.2
|
||||
import QtQuick 2.7
|
||||
|
||||
import NERvGear 1.0 as NVG
|
||||
|
||||
|
||||
|
||||
Item {
|
||||
readonly property var styles: []
|
||||
readonly property var stylesURL: []
|
||||
readonly property var stylesCFG: []
|
||||
|
||||
signal audioDataUpdated(var audioData)
|
||||
signal wsocketClosed()
|
||||
|
||||
function execute(path, args) {
|
||||
path = NVG.Url.toLocalFile(Qt.resolvedUrl(path));
|
||||
NVG.SystemCall.execute(path, args);
|
||||
}
|
||||
|
||||
function openFile(fileUrl) {
|
||||
let request = new XMLHttpRequest();
|
||||
request.open("GET", fileUrl, false);
|
||||
request.send(null);
|
||||
let data = request.responseText;
|
||||
request = null;
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseINIString(data){
|
||||
let regex = {
|
||||
section: /\[\s*([^]*)\s*\]\s*$/,
|
||||
param: /^\s*([\w\.\-\_]+)\s*=\s*(.*?)\s*$/,
|
||||
comment: /^\s*;.*$/
|
||||
};
|
||||
let value = {};
|
||||
let lines = data.split(/\r\n|\r|\n/);
|
||||
let section = null;
|
||||
let match;
|
||||
lines.forEach(function(line){
|
||||
if(regex.comment.test(line)){
|
||||
return;
|
||||
}else if(regex.param.test(line)){
|
||||
match = line.match(regex.param);
|
||||
if(section){
|
||||
value[section][match[1]] = match[2];
|
||||
}else{
|
||||
value[match[1]] = match[2];
|
||||
}
|
||||
}else if(regex.section.test(line)){
|
||||
match = line.match(regex.section);
|
||||
value[match[1]] = {};
|
||||
section = match[1];
|
||||
}else if(line.length === 0 && section){
|
||||
section = null;
|
||||
};
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: wsocket
|
||||
sourceComponent: WSocket {
|
||||
Component.onCompleted: {
|
||||
let ini_data = openFile("../bin/advConfig.ini");
|
||||
ini_data = ini_data.toLowerCase();
|
||||
let cfg = parseINIString(ini_data);
|
||||
if(cfg["server"]["ip"].toLowerCase() === "local") {
|
||||
wsIp = "localhost";
|
||||
} else {
|
||||
wsIp = cfg["server"]["ip"];
|
||||
}
|
||||
wsPort = cfg["server"]["port"];
|
||||
}}
|
||||
active: false
|
||||
}
|
||||
|
||||
function setWsocket(status) {
|
||||
wsocket.active = status;
|
||||
}
|
||||
|
||||
onWsocketClosed: {
|
||||
if (wsocket.active) {
|
||||
console.log("Try to reboot ADVServer...");
|
||||
execute("../bin/ADVServer.exe", "-reboot");
|
||||
wsocket.active = false;
|
||||
wsocket.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
function parse_resource(resource_list, sort) {
|
||||
if (sort)
|
||||
resource_list.sort(function (x, y) {
|
||||
let preset_order = ["Preset Line", "Preset Waves", "Preset Circle", "Preset Solid-circle", "Preset Ordinal Scale UI bottom"];
|
||||
if (preset_order.indexOf(x.title) < preset_order.indexOf(y.title))
|
||||
return -1;
|
||||
else if(preset_order.indexOf(x.title) > preset_order.indexOf(y.title))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
});
|
||||
resource_list.forEach(function (resource) {
|
||||
let name = resource.title;
|
||||
let styleURL = "";
|
||||
let styleCFG = "";
|
||||
resource.files().forEach(function (file) {
|
||||
if (file.entry === "Style.qml") {
|
||||
styleURL = String(file.url);
|
||||
} else if (file.entry === "Config.qml") {
|
||||
styleCFG = String(file.url);
|
||||
}
|
||||
});
|
||||
if (styleURL && stylesURL.indexOf(styleURL) === -1) {
|
||||
styles.push(name);
|
||||
stylesURL.push(styleURL);
|
||||
stylesCFG.push(styleCFG);
|
||||
|
||||
}
|
||||
// console.log(JSON.stringify(Object.keys(resource), null, 2));
|
||||
// console.log(JSON.stringify(resource.files(), null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const preset_list = NVG.Resources.filter(/advp.widget.mashiros.top/, /top.mashiros.advp-style/);
|
||||
parse_resource(preset_list, true);
|
||||
const third_list = NVG.Resources.filter(/.*/, /top.mashiros.advp-style/);
|
||||
parse_resource(third_list, false);
|
||||
// console.log(JSON.stringify(styles, null, 2));
|
||||
// console.log(JSON.stringify(stylesURL, null, 2));
|
||||
}
|
||||
}
|
||||
60
qml/Main.qml
Normal file
60
qml/Main.qml
Normal file
@ -0,0 +1,60 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import NERvGear 1.0 as NVG
|
||||
import NERvGear.Templates 1.0 as T
|
||||
|
||||
import "."
|
||||
|
||||
|
||||
T.Widget {
|
||||
id: widget
|
||||
solid: true
|
||||
title: qsTr("ADV Widget")
|
||||
resizable: true
|
||||
|
||||
editing: styleDialog.active
|
||||
|
||||
property bool initial: true
|
||||
|
||||
function setStyleURL(url) {
|
||||
styleLoader.source = url;
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: styleDialog
|
||||
active: false
|
||||
visible: false
|
||||
sourceComponent: StylePreferences {
|
||||
transientParent: widget.NVG.View.window
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if(initial) {
|
||||
styleDialog.active = false;
|
||||
styleDialog.visible = true;
|
||||
initial = false;
|
||||
} else {
|
||||
item.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: styleLoader
|
||||
active: widget.NVG.View.exposed
|
||||
enabled: true
|
||||
source: ""
|
||||
}
|
||||
|
||||
menu: Menu {
|
||||
Action {
|
||||
text: qsTr("Settings")
|
||||
onTriggered: styleDialog.active = true
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
styleDialog.active = true;
|
||||
}
|
||||
}
|
||||
181
qml/StylePreferences.qml
Normal file
181
qml/StylePreferences.qml
Normal file
@ -0,0 +1,181 @@
|
||||
import QtQuick 2.12
|
||||
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import NERvGear 1.0 as NVG
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "."
|
||||
|
||||
|
||||
NVG.Window {
|
||||
id: window
|
||||
title: qsTr("ADV-Plugin: Settings")
|
||||
visible: false
|
||||
minimumWidth: 480
|
||||
minimumHeight: 580
|
||||
maximumWidth: minimumWidth
|
||||
maximumHeight: minimumHeight
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
Behavior on minimumHeight {
|
||||
PropertyAnimation {
|
||||
duration: 500
|
||||
easing.type: Easing.InOutBack
|
||||
}
|
||||
}
|
||||
|
||||
property var configuration
|
||||
property var old_style_cfg
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
anchors.topMargin: 0
|
||||
|
||||
Row {
|
||||
spacing: 350
|
||||
|
||||
ToolButton {
|
||||
text: qsTr("Save")
|
||||
onClicked: {
|
||||
configuration = rootPreference.save();
|
||||
let index = configuration["index"];
|
||||
widget.settings[Common.stylesURL[index]] = configuration[Common.stylesURL[index]];
|
||||
delete configuration[Common.stylesURL[index]];
|
||||
widget.settings.styles = configuration;
|
||||
widget.settings.current_style = Common.stylesURL[index];
|
||||
styleDialog.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
text: qsTr("Reset")
|
||||
onClicked: {
|
||||
styleLoader.load();
|
||||
let cfg = rootPreference.save();
|
||||
let index = cfg["index"];
|
||||
widget.settings[Common.stylesURL[index]] = cfg[Common.stylesURL[index]];
|
||||
widget.setStyleURL("");
|
||||
widget.setStyleURL(Qt.resolvedUrl(Common.stylesURL[widget.settings.styles["index"]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: qsTr("Settings")
|
||||
font.pixelSize: 24
|
||||
}
|
||||
|
||||
Flickable {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
clip: true
|
||||
contentWidth: preferenceLayout.implicitWidth
|
||||
contentHeight: preferenceLayout.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: preferenceLayout
|
||||
width: root.width
|
||||
|
||||
P.PreferenceGroup {
|
||||
id: rootPreference
|
||||
Layout.fillWidth: true
|
||||
|
||||
label: qsTr("Configuration")
|
||||
|
||||
onPreferenceEdited: {
|
||||
let cfg = rootPreference.save();
|
||||
// console.log(JSON.stringify(cfg, null, 2));
|
||||
let index = cfg["index"];
|
||||
if (widget.settings.styles["index"] !== index) {
|
||||
widget.setStyleURL("");
|
||||
widget.settings[Common.stylesURL[widget.settings.styles["index"]]] = old_style_cfg;
|
||||
old_style_cfg = widget.settings[Common.stylesURL[index]];
|
||||
}
|
||||
|
||||
widget.settings[Common.stylesURL[index]] = cfg[Common.stylesURL[index]];
|
||||
delete cfg[Common.stylesURL[index]];
|
||||
widget.settings.styles = cfg;
|
||||
widget.setStyleURL(Qt.resolvedUrl(Common.stylesURL[index]));
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
id: styleList
|
||||
name: "index"
|
||||
label: qsTr("Styles")
|
||||
icon.name: "solid:\uf1fc"
|
||||
defaultValue: 0
|
||||
model: Common.styles
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.PreferenceLoader {
|
||||
id: styleLoader
|
||||
name: Common.stylesURL[styleList.value]
|
||||
source: Qt.resolvedUrl(Common.stylesCFG[styleList.value])
|
||||
onLoaded: {
|
||||
let cfg = save();
|
||||
if (!widget.settings[Common.stylesURL[styleList.value]]) {
|
||||
widget.settings[Common.stylesURL[styleList.value]] = cfg;
|
||||
} else if(widget.settings[Common.stylesURL[styleList.value]]["__version"] === cfg["__version"]) {
|
||||
load(widget.settings[Common.stylesURL[styleList.value]]);
|
||||
} else {
|
||||
widget.settings[Common.stylesURL[styleList.value]] = cfg;
|
||||
}
|
||||
window.minimumHeight = cfg["__cfg_height"];
|
||||
}
|
||||
|
||||
onContentItemChanged: {
|
||||
if(contentItem) {
|
||||
contentItem.label = Common.styles[styleList.value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
Component.onCompleted: {
|
||||
if(!widget.settings.styles) {
|
||||
configuration = rootPreference.save();
|
||||
let index = configuration["index"];
|
||||
widget.settings[Common.stylesURL[index]] = configuration[Common.stylesURL[index]];
|
||||
old_style_cfg = configuration[Common.stylesURL[index]];
|
||||
delete configuration[Common.stylesURL[index]];
|
||||
widget.settings.current_style = Common.stylesURL[index];
|
||||
widget.settings.styles = configuration;
|
||||
}
|
||||
|
||||
let index = Common.stylesURL.indexOf(widget.settings.current_style);
|
||||
if (index === -1) {
|
||||
index = 0;
|
||||
widget.settings.current_style = Common.stylesURL[index];
|
||||
}
|
||||
|
||||
widget.settings.styles["index"] = index;
|
||||
widget.setStyleURL(Qt.resolvedUrl(Common.stylesURL[widget.settings.styles["index"]]));
|
||||
|
||||
rootPreference.load(widget.settings.styles);
|
||||
configuration = widget.settings.styles;
|
||||
old_style_cfg = widget.settings[Common.stylesURL[index]];
|
||||
|
||||
styleLoader.load(widget.settings[Common.stylesURL[index]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
widget.setStyleURL("");
|
||||
widget.settings[Common.stylesURL[widget.settings.styles["index"]]] = old_style_cfg;
|
||||
widget.settings.styles = configuration;
|
||||
widget.setStyleURL(Qt.resolvedUrl(Common.stylesURL[widget.settings.styles["index"]]));
|
||||
styleDialog.active = false;
|
||||
}
|
||||
}
|
||||
25
qml/WSocket.qml
Normal file
25
qml/WSocket.qml
Normal file
@ -0,0 +1,25 @@
|
||||
import QtWebSockets 1.1
|
||||
|
||||
import "."
|
||||
|
||||
|
||||
WebSocket {
|
||||
property string wsIp: "localhost"
|
||||
property int wsPort: 5050
|
||||
|
||||
url: "ws://" + wsIp + ":" + wsPort
|
||||
active: true
|
||||
|
||||
onStatusChanged: {
|
||||
if(status === WebSocket.Closed || status === WebSocket.Error) {
|
||||
Common.wsocketClosed();
|
||||
}
|
||||
}
|
||||
|
||||
onBinaryMessageReceived: {
|
||||
let arrayBuffer = new Float32Array(message);
|
||||
// Common.audioData = arrayBuffer.slice();
|
||||
Common.audioDataUpdated(arrayBuffer.slice());
|
||||
// arrayBuffer = null;
|
||||
}
|
||||
}
|
||||
41
qml/api/CfgAPI.qml
Normal file
41
qml/api/CfgAPI.qml
Normal file
@ -0,0 +1,41 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
P.DialogPreference {
|
||||
icon.name: "solid:\uf085"
|
||||
live: true
|
||||
property string version: ""
|
||||
property int cfg_height: 580
|
||||
|
||||
P.TextFieldPreference {
|
||||
name: "__version"
|
||||
visible: false
|
||||
enabled: false
|
||||
defaultValue: version
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "__cfg_height"
|
||||
enabled: false
|
||||
visible: false
|
||||
editable: false
|
||||
from: cfg_height
|
||||
to: cfg_height
|
||||
defaultValue: cfg_height
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
text: qsTr("Version")
|
||||
visible: version
|
||||
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: version
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
}
|
||||
33
qml/api/StyleAPI.qml
Normal file
33
qml/api/StyleAPI.qml
Normal file
@ -0,0 +1,33 @@
|
||||
import QtQuick 2.12
|
||||
|
||||
import ".." //显式导入单例Common.qml
|
||||
|
||||
Canvas {
|
||||
width: widget.width;
|
||||
height: widget.height;
|
||||
contextType: "2d";
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
|
||||
signal audioDataUpdeted(var data)
|
||||
signal configsUpdated()
|
||||
property var configs: widget.settings[Common.stylesURL[widget.settings.styles["index"]]]
|
||||
|
||||
onConfigsChanged: {
|
||||
if (context) {
|
||||
configsUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
onContextChanged: {
|
||||
if (context) {
|
||||
configsUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: Boolean(context)
|
||||
target: Common
|
||||
onAudioDataUpdated: audioDataUpdeted(audioData)
|
||||
}
|
||||
}
|
||||
1
qml/qmldir
Normal file
1
qml/qmldir
Normal file
@ -0,0 +1 @@
|
||||
singleton Common 1.0 Common.qml
|
||||
65
readme.md
Normal file
65
readme.md
Normal file
@ -0,0 +1,65 @@
|
||||
<div align="center"><h1>ADV-Plugin</h1></div>
|
||||
<div align="center"><img src="https://p.qlogo.cn/zc_icon/0/0afa95dfc4850ec9539eb0800b61a15016277179577515/0.png"></div>
|
||||
<div align="center">Powered By <a href="http://mashiros.top">Mashiro_Sorata</a></div>
|
||||
|
||||
---
|
||||
|
||||
# 简介
|
||||
|
||||
`ADV-Plugin`是[SAO Utils 2](http://sao.gpbeta.com/)的第三方插件,可以提供系统音频数据的可视化服务。
|
||||
得益于SAO Utils 2允许用户使用qml脚本编写扩展插件,相对于[第一代](https://github.com/Mashiro-Sorata/AudioDVServer-Plugin)的插件方案,第二代可以整合第一代中客户端与服务器端的功能,无需复杂的配置即可使用。
|
||||
|
||||
## 特色
|
||||
* 整合客户端与服务器端的功能,使用更简单
|
||||
* 预设4种频谱显示形式,其中每种都可以进一步自定义设置其样式
|
||||
* 提供了Style的开发接口,供开发者添加更多的可视化样式
|
||||
* 导入第三方Style类似其他插件,预计支持steam创意工坊下载
|
||||
* 服务端崩溃后自启动
|
||||
|
||||
## 使用说明
|
||||
|
||||
安装并启用插件后,默认加载第一种预设Style样式。右键挂件可调出菜单,在挂件菜单的挂件名选单中点击Settings选项,呼出Style设置窗口。点击其中的Styles选项可切换不同的Style风格,若此Style提供可配置项,则在Styles选项下方会出现配置界面的入口。
|
||||
|
||||
<div align="center"><img src="https://p.qlogo.cn/zc_icon/0/5c7aacc6a0ddcb889bdacabdbf3a466716282394846386/0.png" style="zoom:80%;" /></div>
|
||||
|
||||
# 进阶设置
|
||||
|
||||
样式设置可在插件内设置,一般服务端设置采用默认设置即可,但也提供了服务端设置的接口作为高级设置。可通过更改本插件目录`bin`文件夹中的`advConfig.ini`文件来配置插件服务器与数据设置。当配置数据错误或无配置文件时使用默认值,配置值不区分大小写。其参数的具体说明如下。
|
||||
|
||||
- [Server]
|
||||
- `ip`:可选,默认值为`local`,指代地址127.0.0.1,可更改为`any`,指代地址0.0.0.0。只支持`any`与默认参数`local`,定义插件提供服务的地址。
|
||||
- `port`:可选,默认值为`5050`,定义插件提供服务的端口号。
|
||||
- `maxClient`:可选,默认值为`5`,定义WebSocket的最大连接数。
|
||||
- `logger`:可选,默认值为`false`。设置为`true`后可在插件所在目录下输出日志文件`ADV_Log.log`。
|
||||
- [FFT]
|
||||
- `attack`:可选,默认值为25。可调节频谱数据增大时的速度,该值越大,增大速度越慢。
|
||||
- `decay`:可选,默认值为25。可调节频谱数据减小时的速度,该值越大,减小速度越慢。
|
||||
- `norspeed`:可选,默认值为1。动态归一化系数,取值范围从1~99,该值越大,归一化的峰值数据收敛速度越快。
|
||||
- `peakthr`:可选,默认值为10。归一化的峰值数据的额外增量。
|
||||
- `fps`:可选,默认值为30。每秒钟数据发送的次数,**<font color='red'>必须确保该值大于5</font>**。
|
||||
- `changeSpeed`:可选,默认值为25。按照`changeSpeed/fps`的比例调节频谱数据变化速度,**一般该值小于fps**。
|
||||
|
||||
|
||||
`advConfig.ini` 文件示例:
|
||||
```ini
|
||||
[Server]
|
||||
ip = local
|
||||
port = 5050
|
||||
maxClient = 5
|
||||
logger = true
|
||||
|
||||
[FFT]
|
||||
attack = 25
|
||||
decay = 25
|
||||
norspeed = 1
|
||||
peakthr = 10
|
||||
fps = 35
|
||||
changeSpeed = 25
|
||||
```
|
||||
|
||||
# 频谱样式开发
|
||||
|
||||
如果想开发新的频谱样式,可以参照[ADV-Plugin Wiki](https://github.com/Mashiro-Sorata/ADV-Plugin/wiki)的说明及开发教程。
|
||||
|
||||
欢迎开发更多有趣好玩的频谱样式,与大家分享~
|
||||
|
||||
111
styles/Preset_Ordinal_Scale_UI_bottom/Config.qml
Normal file
111
styles/Preset_Ordinal_Scale_UI_bottom/Config.qml
Normal file
@ -0,0 +1,111 @@
|
||||
import QtQuick 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "../../qml/api" //导入CfgAPI.qml
|
||||
|
||||
CfgAPI {
|
||||
version: "1.0.0"
|
||||
cfg_height: 710
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Bass Color"
|
||||
label: qsTr("Bass Line Color")
|
||||
defaultValue: "#DC143C"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Alto Color"
|
||||
label: qsTr("Alto Line Color")
|
||||
defaultValue: "#F8F8FF"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Treble Color"
|
||||
label: qsTr("Treble Line Color")
|
||||
defaultValue: "#4169E1"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Bass AM"
|
||||
label: qsTr("Bass Amplitude")
|
||||
from: 10
|
||||
to: 300
|
||||
stepSize: 5
|
||||
defaultValue: 100
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Alto AM"
|
||||
label: qsTr("Alto Amplitude")
|
||||
from: 10
|
||||
to: 300
|
||||
stepSize: 5
|
||||
defaultValue: 150
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Treble AM"
|
||||
label: qsTr("Treble Amplitude")
|
||||
from: 10
|
||||
to: 300
|
||||
stepSize: 5
|
||||
defaultValue: 200
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Static AM"
|
||||
label: qsTr("Static Amplitude")
|
||||
from: 5
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 15
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Speed"
|
||||
label: qsTr("Wave Speed")
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 20
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Data Settings"
|
||||
label: qsTr("Data Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_osui_dataSettings_autoNormalizing
|
||||
name: "Auto Normalizing"
|
||||
label: qsTr("Auto Normalizing")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Amplitude"
|
||||
label: qsTr("Amplitude Ratio")
|
||||
enabled: !_cfg_preset_osui_dataSettings_autoNormalizing.value
|
||||
message: "1 to 100"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 1
|
||||
to: 100
|
||||
defaultValue: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
123
styles/Preset_Ordinal_Scale_UI_bottom/Style.qml
Normal file
123
styles/Preset_Ordinal_Scale_UI_bottom/Style.qml
Normal file
File diff suppressed because one or more lines are too long
139
styles/Preset_circle/Config.qml
Normal file
139
styles/Preset_circle/Config.qml
Normal file
@ -0,0 +1,139 @@
|
||||
import QtQuick 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "../../qml/api" //导入CfgAPI.qml
|
||||
|
||||
CfgAPI {
|
||||
version: "1.0.0"
|
||||
cfg_height: 740
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Main Color"
|
||||
label: qsTr("Spectrum Line Color")
|
||||
defaultValue: "#FF4500"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Line Position"
|
||||
label: qsTr("Spectrum Line Position")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Both"), qsTr("Outside"), qsTr("Inside")]
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Width"
|
||||
label: qsTr("Spectrum Line Width")
|
||||
from: 0.1
|
||||
to: 10
|
||||
stepSize: 0.1
|
||||
defaultValue: 1
|
||||
displayValue: value.toFixed(1) + "px"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Max Range"
|
||||
label: qsTr("Max Amplitude")
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 50
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Data Length"
|
||||
label: qsTr("Spectrum Length")
|
||||
defaultValue: 0
|
||||
model: [64, 32, 16, 8]
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Channel"
|
||||
label: qsTr("Channel")
|
||||
message: "1 to 2"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: false
|
||||
from: 1
|
||||
to: 2
|
||||
defaultValue: 2
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
name: "Reverse"
|
||||
label: qsTr("Reverse Spectrum")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_rotate
|
||||
name: "Rotate"
|
||||
label: qsTr("Auto Rotate")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Ratate Speed"
|
||||
label: qsTr("Ratate Speed")
|
||||
enabled: _cfg_preset_line_rotate.value
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 10
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Angle"
|
||||
label: qsTr("Initial Angle")
|
||||
message: "0 to 359"
|
||||
enabled: !_cfg_preset_line_rotate.value
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 0
|
||||
to: 359
|
||||
defaultValue: 0
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Data Settings"
|
||||
label: qsTr("Data Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_circle_dataSettings_autoNormalizing
|
||||
name: "Auto Normalizing"
|
||||
label: qsTr("Auto Normalizing")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Amplitude"
|
||||
label: qsTr("Amplitude Ratio")
|
||||
enabled: !_cfg_preset_circle_dataSettings_autoNormalizing.value
|
||||
message: "1 to 100"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 1
|
||||
to: 100
|
||||
defaultValue: 10
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Unit Style"
|
||||
label: qsTr("Display Style")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Linear"), qsTr("Decibel")]
|
||||
}
|
||||
}
|
||||
}
|
||||
132
styles/Preset_circle/Style.qml
Normal file
132
styles/Preset_circle/Style.qml
Normal file
@ -0,0 +1,132 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import "../../qml/api"
|
||||
|
||||
StyleAPI {
|
||||
readonly property var audioData: new Array(128)
|
||||
|
||||
//configs
|
||||
readonly property string color: configs["Main Color"]
|
||||
readonly property int linePosition: configs["Line Position"]
|
||||
readonly property real lineWidth: configs["Line Width"]
|
||||
readonly property real maxRange: configs["Max Range"] / 100
|
||||
readonly property int uDataLen: Math.pow(2, configs["Data Length"])
|
||||
readonly property int dataLength: 64/uDataLen
|
||||
readonly property int channel: configs["Channel"]
|
||||
readonly property bool reverse: configs["Reverse"]
|
||||
readonly property bool rotateFlag: configs["Rotate"]
|
||||
readonly property real rSpeed: configs["Ratate Speed"] / 100
|
||||
readonly property real angle: configs["Angle"]
|
||||
readonly property bool autoNormalizing: configs["Data Settings"]["Auto Normalizing"]
|
||||
readonly property real amplitude: configs["Data Settings"]["Amplitude"] / 400
|
||||
readonly property int unitStyle: configs["Data Settings"]["Unit Style"]
|
||||
|
||||
readonly property int total: channel*dataLength
|
||||
|
||||
readonly property real dotGap: 360/total
|
||||
property real offsetAngle: 0
|
||||
property var outerPos: []
|
||||
property var innerPos: []
|
||||
readonly property real degUnit: Math.PI/180
|
||||
|
||||
readonly property real subRatio: 0.2*maxRange
|
||||
readonly property real mainRatio: 1-subRatio*2.5
|
||||
|
||||
readonly property real minLength: Math.min(width, height)
|
||||
readonly property real ratio:minLength*subRatio
|
||||
readonly property real halfWidth: width/2
|
||||
readonly property real halfHeight: height/2
|
||||
readonly property real halfMinLength: minLength/2
|
||||
readonly property real logAmplitude: Math.log10(amplitude)
|
||||
|
||||
|
||||
onConfigsUpdated: {
|
||||
context.lineWidth = lineWidth;
|
||||
context.strokeStyle = color;
|
||||
}
|
||||
|
||||
function getPos(r, deg) {
|
||||
return [halfWidth+Math.cos(deg)*r,halfHeight+Math.sin(deg)*r];
|
||||
}
|
||||
|
||||
function createPoint() {
|
||||
outerPos = [];
|
||||
innerPos = [];
|
||||
let deg, deltaR, r1, r2, _rhmLen;
|
||||
_rhmLen = mainRatio*halfMinLength;
|
||||
|
||||
for (let j=0; j < channel; j++) {
|
||||
for (let i=0; i < dataLength; i++) {
|
||||
deg = degUnit*((i+j*dataLength)*dotGap + offsetAngle);
|
||||
deltaR = audioData[reverse*(dataLength-i-1)+(!reverse)*(i+j*dataLength)] * ratio;
|
||||
r1 = _rhmLen+1+deltaR*(linePosition!==2);
|
||||
r2 = _rhmLen-1-deltaR*(linePosition!==1);
|
||||
outerPos.push(getPos(r1, deg));
|
||||
innerPos.push(getPos(r2, deg));
|
||||
}
|
||||
}
|
||||
offsetAngle = rotateFlag ? ((offsetAngle + rSpeed) % 360) : angle;
|
||||
}
|
||||
|
||||
onAudioDataUpdeted: {
|
||||
if(autoNormalizing) {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
let logPeak = Math.log10(data[128]);
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.4 * (Math.log10(data[i*uDataLen+j])-logPeak) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[i*uDataLen+j] / data[128];
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.35 * (Math.log10(data[i*uDataLen+j])+logAmplitude) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[i*uDataLen+j] * amplitude;
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
context.clearRect(0, 0, width, height);
|
||||
createPoint();
|
||||
|
||||
context.beginPath();
|
||||
for(let i=0; i<total; i++) {
|
||||
context.moveTo(outerPos[i][0], outerPos[i][1]);
|
||||
context.lineTo(innerPos[i][0], innerPos[i][1]);
|
||||
}
|
||||
context.stroke();
|
||||
requestPaint();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
for (let i = 0; i < 128; i++) {
|
||||
audioData[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
150
styles/Preset_line/Config.qml
Normal file
150
styles/Preset_line/Config.qml
Normal file
@ -0,0 +1,150 @@
|
||||
import QtQuick 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "../../qml/api" //导入CfgAPI.qml
|
||||
|
||||
CfgAPI {
|
||||
version: "1.0.0"
|
||||
cfg_height: 580
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_Center_Line
|
||||
name: "Center Line"
|
||||
label: qsTr("Show Center Line")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Center Color"
|
||||
label: qsTr("Center Line Color")
|
||||
enabled: _cfg_preset_line_Center_Line.value
|
||||
defaultValue: "#FF4500"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Line Color"
|
||||
label: qsTr("Spectrum Line Color")
|
||||
defaultValue: "#FF4500"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Line Position"
|
||||
label: qsTr("Spectrum Line Position")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Both"), qsTr("Up"), qsTr("Down")]
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Data Length"
|
||||
label: qsTr("Spectrum Length")
|
||||
defaultValue: 0
|
||||
model: [64, 32, 16, 8]
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SpinPreference {
|
||||
id: _cfg_preset_line_Channel
|
||||
name: "Channel"
|
||||
label: qsTr("Channel")
|
||||
message: "1 to 2"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: false
|
||||
from: 1
|
||||
to: 2
|
||||
defaultValue: 2
|
||||
}
|
||||
|
||||
P.SwitchPreference {
|
||||
name: "Reverse"
|
||||
label: qsTr("Reverse Spectrum")
|
||||
enabled: _cfg_preset_line_Channel.value === 1
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Rotate Settings"
|
||||
label: qsTr("Rotate Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_Rotate_Center_Enable
|
||||
name: "Center Enable"
|
||||
label: qsTr("Rotate Center Line")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Center Angle"
|
||||
label: qsTr("Angle of Center Line")
|
||||
enabled: _cfg_preset_line_Rotate_Center_Enable.value
|
||||
from: -30
|
||||
to: 30
|
||||
stepSize: 1
|
||||
defaultValue: 10
|
||||
displayValue: value + "°"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_Rotate_Line_Enable
|
||||
name: "Line Enable"
|
||||
label: qsTr("Rotate Spectrum Line")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Angle"
|
||||
label: qsTr("Angle of Spectrum Line")
|
||||
enabled: _cfg_preset_line_Rotate_Line_Enable.value
|
||||
from: -30
|
||||
to: 30
|
||||
stepSize: 1
|
||||
defaultValue: 10
|
||||
displayValue: value + "°"
|
||||
}
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Data Settings"
|
||||
label: qsTr("Data Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_dataSettings_autoNormalizing
|
||||
name: "Auto Normalizing"
|
||||
label: qsTr("Auto Normalizing")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Amplitude"
|
||||
label: qsTr("Amplitude Ratio")
|
||||
enabled: !_cfg_preset_line_dataSettings_autoNormalizing.value
|
||||
message: "1 to 100"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 1
|
||||
to: 100
|
||||
defaultValue: 10
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Unit Style"
|
||||
label: qsTr("Display Style")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Linear"), qsTr("Decibel")]
|
||||
}
|
||||
}
|
||||
}
|
||||
163
styles/Preset_line/Style.qml
Normal file
163
styles/Preset_line/Style.qml
Normal file
@ -0,0 +1,163 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import "../../qml/api"
|
||||
|
||||
StyleAPI {
|
||||
readonly property var audioData: new Array(128)
|
||||
|
||||
readonly property bool centerLineFlag: configs["Center Line"]
|
||||
readonly property string center_color: configs["Center Color"]
|
||||
readonly property string line_color: configs["Line Color"]
|
||||
readonly property int linePosition: configs["Line Position"]
|
||||
readonly property int uDataLen: Math.pow(2, configs["Data Length"]);
|
||||
readonly property int dataLength: 64/uDataLen
|
||||
readonly property int channel: configs["Channel"]
|
||||
readonly property bool reverse: configs["Reverse"]
|
||||
readonly property bool centerRotateFlag: configs["Rotate Settings"]["Center Enable"]
|
||||
readonly property real centerRotateAngle: configs["Rotate Settings"]["Center Angle"]
|
||||
readonly property bool lineRotateFlag: configs["Rotate Settings"]["Line Enable"]
|
||||
readonly property real lineRotateAngle: configs["Rotate Settings"]["Line Angle"]
|
||||
readonly property bool autoNormalizing: configs["Data Settings"]["Auto Normalizing"]
|
||||
readonly property real amplitude: configs["Data Settings"]["Amplitude"] / 400.0
|
||||
readonly property int unitStyle: configs["Data Settings"]["Unit Style"]
|
||||
|
||||
property int total: channel * dataLength
|
||||
property real logAmplitude: Math.log10(amplitude)
|
||||
property real degUnit: Math.PI / 180
|
||||
|
||||
property real halfWidth: width/2
|
||||
property real halfHeight: height/2
|
||||
|
||||
onAudioDataUpdeted: {
|
||||
if(autoNormalizing) {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
for(let i=0; i<dataLength; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.4 * (Math.log10(data[64-i*uDataLen-j-1]/data[128])) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
if (channel === 2) {
|
||||
for(let i=dataLength; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.4 * (Math.log10(data[64+(i-dataLength)*uDataLen+j]/data[128])) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<dataLength; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[64-i*uDataLen-j-1];
|
||||
}
|
||||
audioData[i] /= (uDataLen * data[128]);
|
||||
}
|
||||
if (channel === 2) {
|
||||
for(let i=dataLength; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[64+(i-dataLength)*uDataLen+j];
|
||||
}
|
||||
audioData[i] /= (uDataLen * data[128]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
for(let i=0; i<dataLength; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.35 * (Math.log10(data[64-i*uDataLen-j-1])+logAmplitude) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
if (channel === 2) {
|
||||
for(let i=dataLength; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.35 * (Math.log10(data[64+(i-dataLength)*uDataLen+j])+logAmplitude) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<dataLength; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[64-i*uDataLen-j-1];
|
||||
}
|
||||
audioData[i] /= (uDataLen/amplitude);
|
||||
}
|
||||
if (channel === 2) {
|
||||
for(let i=dataLength; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[64+(i-dataLength)*uDataLen+j];
|
||||
}
|
||||
audioData[i] /= (uDataLen/amplitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let _dy;
|
||||
let _y_dy = centerRotateFlag*Math.tan(centerRotateAngle*degUnit)*halfWidth;
|
||||
let _ux = width/total;
|
||||
let _dx = Math.round(_ux/2);
|
||||
let _y = halfHeight-_y_dy
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
|
||||
if(lineRotateFlag || centerRotateFlag) {
|
||||
context.transform(1, centerRotateFlag*centerRotateAngle * degUnit, -lineRotateFlag*lineRotateAngle * degUnit, 1, lineRotateFlag*Math.sin(1.05*lineRotateAngle*degUnit)*_y, 0);
|
||||
}
|
||||
|
||||
if (centerLineFlag) {
|
||||
context.fillStyle = center_color;
|
||||
context.fillRect(0, _y, width, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
context.fillStyle = line_color;
|
||||
|
||||
//绘制频谱
|
||||
if (channel === 1 && reverse) {
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
let index = dataLength - i - 1;
|
||||
_y = halfHeight*(1-(linePosition!==2)*audioData[index])-_y_dy;
|
||||
_dy = (halfHeight + (!linePosition)*halfHeight)*audioData[index];
|
||||
context.fillRect(_ux * i, _y, _dx, _dy);
|
||||
}
|
||||
} else {
|
||||
for (let j = 0; j < channel; j++) {
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
let index = j ? ((total - dataLength) + i) : i;
|
||||
_y = halfHeight*(1-(linePosition!==2)*audioData[index])-_y_dy;
|
||||
_dy = (halfHeight + (!linePosition)*halfHeight)*audioData[index];
|
||||
context.fillRect(_ux * (i + j * dataLength), _y, _dx, _dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (centerRotateFlag || lineRotateFlag)
|
||||
context.resetTransform();
|
||||
|
||||
context.fill();
|
||||
|
||||
requestPaint();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
for (let i = 0; i < 128; i++) {
|
||||
audioData[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
139
styles/Preset_solidcircle/Config.qml
Normal file
139
styles/Preset_solidcircle/Config.qml
Normal file
@ -0,0 +1,139 @@
|
||||
import QtQuick 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "../../qml/api" //导入CfgAPI.qml
|
||||
|
||||
CfgAPI {
|
||||
version: "1.0.0"
|
||||
cfg_height: 740
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Main Color"
|
||||
label: qsTr("Spectrum Line Color")
|
||||
defaultValue: "#FF4500"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Line Position"
|
||||
label: qsTr("Spectrum Line Position")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Both"), qsTr("Outside"), qsTr("Inside")]
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Width"
|
||||
label: qsTr("Spectrum Line Width")
|
||||
from: 0.1
|
||||
to: 4
|
||||
stepSize: 0.1
|
||||
defaultValue: 1
|
||||
displayValue: value.toFixed(1) + "px"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Max Range"
|
||||
label: qsTr("Max Amplitude")
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 50
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Data Length"
|
||||
label: qsTr("Spectrum Length")
|
||||
defaultValue: 0
|
||||
model: [64, 32, 16, 8]
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Channel"
|
||||
label: qsTr("Channel")
|
||||
message: "1 to 2"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: false
|
||||
from: 1
|
||||
to: 2
|
||||
defaultValue: 2
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
name: "Reverse"
|
||||
label: qsTr("Reverse Spectrum")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_rotate
|
||||
name: "Rotate"
|
||||
label: qsTr("Auto Rotate")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Ratate Speed"
|
||||
label: qsTr("Ratate Speed")
|
||||
enabled: _cfg_preset_line_rotate.value
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 10
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Angle"
|
||||
label: qsTr("Initial Angle")
|
||||
message: "0 to 359"
|
||||
enabled: !_cfg_preset_line_rotate.value
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 0
|
||||
to: 359
|
||||
defaultValue: 0
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Data Settings"
|
||||
label: qsTr("Data Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_solidcircle_dataSettings_autoNormalizing
|
||||
name: "Auto Normalizing"
|
||||
label: qsTr("Auto Normalizing")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Amplitude"
|
||||
label: qsTr("Amplitude Ratio")
|
||||
enabled: !_cfg_preset_solidcircle_dataSettings_autoNormalizing.value
|
||||
message: "1 to 100"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 1
|
||||
to: 100
|
||||
defaultValue: 10
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Unit Style"
|
||||
label: qsTr("Display Style")
|
||||
defaultValue: 0
|
||||
model: [qsTr("Linear"), qsTr("Decibel")]
|
||||
}
|
||||
}
|
||||
}
|
||||
149
styles/Preset_solidcircle/Style.qml
Normal file
149
styles/Preset_solidcircle/Style.qml
Normal file
@ -0,0 +1,149 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import "../../qml/api"
|
||||
|
||||
StyleAPI {
|
||||
readonly property var audioData: new Array(128)
|
||||
|
||||
//configs
|
||||
readonly property string color: configs["Main Color"]
|
||||
readonly property int linePosition: configs["Line Position"]
|
||||
readonly property real lineWidth: configs["Line Width"]
|
||||
readonly property real maxRange: configs["Max Range"] / 100
|
||||
readonly property int uDataLen: Math.pow(2, configs["Data Length"])
|
||||
readonly property int dataLength: 64/uDataLen
|
||||
readonly property int channel: configs["Channel"]
|
||||
readonly property bool reverse: configs["Reverse"]
|
||||
readonly property bool rotateFlag: configs["Rotate"]
|
||||
readonly property real rSpeed: configs["Ratate Speed"] / 100
|
||||
readonly property real angle: configs["Angle"]
|
||||
readonly property bool autoNormalizing: configs["Data Settings"]["Auto Normalizing"]
|
||||
readonly property real amplitude: configs["Data Settings"]["Amplitude"] / 400
|
||||
readonly property int unitStyle: configs["Data Settings"]["Unit Style"]
|
||||
|
||||
readonly property int total: channel*dataLength
|
||||
|
||||
readonly property real dotGap: 360/total
|
||||
property real offsetAngle: 0
|
||||
property var outerPos: []
|
||||
property var innerPos: []
|
||||
readonly property real degUnit: Math.PI/180
|
||||
|
||||
readonly property real subRatio: 0.2*maxRange
|
||||
readonly property real mainRatio: 1-subRatio*2.5
|
||||
|
||||
readonly property real minLength: Math.min(width, height)
|
||||
readonly property real ratio:minLength*subRatio
|
||||
readonly property real halfWidth: width/2
|
||||
readonly property real halfHeight: height/2
|
||||
readonly property real halfMinLength: minLength/2
|
||||
readonly property real logAmplitude: Math.log10(amplitude)
|
||||
|
||||
|
||||
onConfigsUpdated: {
|
||||
context.lineWidth = lineWidth;
|
||||
context.strokeStyle = color;
|
||||
}
|
||||
|
||||
function getPos(r, deg) {
|
||||
return [halfWidth+Math.cos(deg)*r,halfHeight+Math.sin(deg)*r];
|
||||
}
|
||||
|
||||
function createPoint() {
|
||||
outerPos = [];
|
||||
innerPos = [];
|
||||
let deg, deltaR, r1, r2, _rhmLen;
|
||||
_rhmLen = mainRatio*halfMinLength;
|
||||
|
||||
for (let j=0; j < channel; j++) {
|
||||
for (let i=0; i < dataLength; i++) {
|
||||
deg = degUnit*((i+j*dataLength)*dotGap + offsetAngle);
|
||||
deltaR = audioData[reverse*(dataLength-i-1)+(!reverse)*(i+j*dataLength)] * ratio;
|
||||
r1 = _rhmLen+1+deltaR*(linePosition!==2);
|
||||
r2 = _rhmLen-1-deltaR*(linePosition!==1);
|
||||
outerPos.push(getPos(r1, deg));
|
||||
innerPos.push(getPos(r2, deg));
|
||||
}
|
||||
}
|
||||
offsetAngle = rotateFlag ? ((offsetAngle + rSpeed) % 360) : angle;
|
||||
}
|
||||
|
||||
onAudioDataUpdeted: {
|
||||
if(autoNormalizing) {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
let logPeak = Math.log10(data[128]);
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.4 * (Math.log10(data[i*uDataLen+j])-logPeak) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[i*uDataLen+j] / data[128];
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (unitStyle) {
|
||||
//对数化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += Math.max(0, 0.35 * (Math.log10(data[i*uDataLen+j])+logAmplitude) + 1.0);
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<total; i++) {
|
||||
audioData[i] = 0;
|
||||
for(let j=0; j<uDataLen; j++) {
|
||||
audioData[i] += data[i*uDataLen+j] * amplitude;
|
||||
}
|
||||
audioData[i] /= uDataLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
createPoint();
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(outerPos[0][0], outerPos[0][1]);
|
||||
for(let i=0; i<total; i++) {
|
||||
context.lineTo(outerPos[i][0], outerPos[i][1]);
|
||||
}
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(innerPos[0][0], innerPos[0][1]);
|
||||
for(let i=0; i<total; i++) {
|
||||
context.lineTo(innerPos[i][0], innerPos[i][1]);
|
||||
}
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.beginPath();
|
||||
for(let i=0; i<total; i++) {
|
||||
context.moveTo(outerPos[i][0], outerPos[i][1]);
|
||||
context.lineTo(innerPos[i][0], innerPos[i][1]);
|
||||
}
|
||||
context.stroke();
|
||||
requestPaint();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
for (let i = 0; i < 128; i++) {
|
||||
audioData[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
styles/Preset_waves/Config.qml
Normal file
53
styles/Preset_waves/Config.qml
Normal file
@ -0,0 +1,53 @@
|
||||
import QtQuick 2.12
|
||||
import NERvGear.Preferences 1.0 as P
|
||||
|
||||
import "../../qml/api" //导入CfgAPI.qml
|
||||
|
||||
CfgAPI {
|
||||
version: "1.0.0"
|
||||
cfg_height: 580
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Width"
|
||||
label: qsTr("Spectrum Line Width")
|
||||
from: 0.1
|
||||
to: 4
|
||||
stepSize: 0.1
|
||||
defaultValue: 1
|
||||
displayValue: value.toFixed(1) + "px"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Line Color"
|
||||
label: qsTr("Spectrum Line Color")
|
||||
defaultValue: "#FF4500"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.DialogPreference {
|
||||
name: "Data Settings"
|
||||
label: qsTr("Data Settings")
|
||||
live: true
|
||||
icon.name: "regular:\uf1de"
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_preset_line_dataSettings_autoNormalizing
|
||||
name: "Auto Normalizing"
|
||||
label: qsTr("Auto Normalizing")
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SpinPreference {
|
||||
name: "Amplitude"
|
||||
label: qsTr("Amplitude Ratio")
|
||||
enabled: !_cfg_preset_line_dataSettings_autoNormalizing.value
|
||||
message: "1 to 100"
|
||||
display: P.TextFieldPreference.ExpandLabel
|
||||
editable: true
|
||||
from: 1
|
||||
to: 100
|
||||
defaultValue: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
62
styles/Preset_waves/Style.qml
Normal file
62
styles/Preset_waves/Style.qml
Normal file
@ -0,0 +1,62 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import "../../qml/api"
|
||||
|
||||
StyleAPI {
|
||||
readonly property var audioData: new Array(128)
|
||||
|
||||
readonly property real lineWidth: configs["Line Width"]
|
||||
readonly property string line_color: configs["Line Color"]
|
||||
readonly property bool autoNormalizing: configs["Data Settings"]["Auto Normalizing"]
|
||||
readonly property real amplitude: configs["Data Settings"]["Amplitude"] / 400.0
|
||||
|
||||
readonly property real ux: width/129
|
||||
readonly property real halfHeight: height/2
|
||||
|
||||
onConfigsUpdated: {
|
||||
context.lineWidth = lineWidth;
|
||||
context.strokeStyle = line_color;
|
||||
}
|
||||
|
||||
onAudioDataUpdeted: {
|
||||
data[128] *= 2;
|
||||
if(autoNormalizing) {
|
||||
//线性化显示
|
||||
for(let i=0; i<64; i++) {
|
||||
audioData[i] = data[64-i-1] / data[128];
|
||||
}
|
||||
for(let i=64; i<128; i++) {
|
||||
audioData[i] = data[i] / data[128];
|
||||
}
|
||||
} else {
|
||||
//线性化显示
|
||||
for(let i=0; i<64; i++) {
|
||||
audioData[i] = data[64-i-1] * amplitude;
|
||||
}
|
||||
for(let i=64; i<128; i++) {
|
||||
audioData[i] = data[i] * amplitude;
|
||||
}
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(0, halfHeight);
|
||||
for(let i=0; i<128; i+=2) {
|
||||
context.lineTo(ux*i, halfHeight*(1+audioData[i]));
|
||||
context.lineTo(ux*(i+1), halfHeight*(1-audioData[i+1]));
|
||||
}
|
||||
context.lineTo(width, halfHeight);
|
||||
// context.closePath();
|
||||
context.stroke();
|
||||
|
||||
requestPaint();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
for (let i = 0; i < 128; i++) {
|
||||
audioData[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user