forked from Mashiro_Sorata/ADV-Plugin
SO_RA
3 years ago
commit
5e720d2995
41 changed files with 2000 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
{ |
||||
"source": "nvg://advp.widget.mashiros.top/widget", |
||||
"settings": "settings.xml" |
||||
} |
After Width: | Height: | Size: 4.2 KiB |
@ -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> |
@ -0,0 +1,4 @@
|
||||
{ |
||||
"source": "nvg://advp.widget.mashiros.top/widget", |
||||
"settings": "settings.xml" |
||||
} |
After Width: | Height: | Size: 2.4 KiB |
@ -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> |
@ -0,0 +1,4 @@
|
||||
{ |
||||
"source": "nvg://advp.widget.mashiros.top/widget", |
||||
"settings": "settings.xml" |
||||
} |
After Width: | Height: | Size: 14 KiB |
@ -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> |
@ -0,0 +1,4 @@
|
||||
{ |
||||
"source": "nvg://advp.widget.mashiros.top/widget", |
||||
"settings": "settings.xml" |
||||
} |
After Width: | Height: | Size: 6.6 KiB |
@ -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> |
@ -0,0 +1,4 @@
|
||||
{ |
||||
"source": "nvg://advp.widget.mashiros.top/widget", |
||||
"settings": "settings.xml" |
||||
} |
After Width: | Height: | Size: 4.6 KiB |
@ -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> |
Binary file not shown.
@ -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 |
@ -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"); |
||||
} |
||||
} |
@ -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" |
||||
} |
||||
] |
||||
} |
After Width: | Height: | Size: 2.4 KiB |
@ -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)); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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 |
||||
} |
||||
} |
||||
} |
@ -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) |
||||
} |
||||
} |
@ -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)的说明及开发教程。 |
||||
|
||||
欢迎开发更多有趣好玩的频谱样式,与大家分享~ |
||||
|
@ -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 |
||||
} |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -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")] |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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")] |
||||
} |
||||
} |
||||
} |