页面优化
This commit is contained in:
@@ -35,7 +35,7 @@ export default function BottomNav() {
|
||||
|
||||
return (
|
||||
<nav
|
||||
className="fixed bottom-0 left-0 right-0 z-50 lg:hidden"
|
||||
className="fixed bottom-0 left-0 right-0 z-50"
|
||||
style={{
|
||||
background: "rgba(10, 10, 12, 0.96)",
|
||||
backdropFilter: "blur(40px) saturate(200%)",
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
class Coeff{
|
||||
constructor() {
|
||||
this.b0 = 0;
|
||||
this.b1 = 0;
|
||||
this.b2 = 0;
|
||||
this.a0 = 0;
|
||||
this.a1 = 0;
|
||||
this.a2 = 0;
|
||||
}
|
||||
|
||||
setB0(value){
|
||||
this.b0 = value;
|
||||
}
|
||||
|
||||
setB1(value){
|
||||
this.b1 = value;
|
||||
}
|
||||
|
||||
setB2(value){
|
||||
this.b2 = value;
|
||||
}
|
||||
|
||||
setA0(value){
|
||||
this.a0 = value;
|
||||
}
|
||||
|
||||
setA1(value){
|
||||
this.a1 = value;
|
||||
}
|
||||
|
||||
setA2(value){
|
||||
this.a2 = value;
|
||||
}
|
||||
|
||||
getSectionsMatrix(gain, fc, bw, type, bypass, fs){
|
||||
const w = 2 * fc / fs;
|
||||
const q = fc / bw;
|
||||
const bypassStatus = bypass ? 1 : 0;
|
||||
const bqtype = type + bypassStatus * 10;
|
||||
const sA = Math.pow(10, gain / 40);
|
||||
const sqrt_sA = Math.sqrt(sA);
|
||||
const sin_w = Math.sin(Math.PI * w);
|
||||
const cos_w = Math.cos(Math.PI * w);
|
||||
const alpha = sin_w / (2 * q);
|
||||
|
||||
let b0, b1, b2, a0, a1, a2;
|
||||
}
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
export const TYPE_PEAK = 0;
|
||||
export const TYPE_LOWSHELF = 1;
|
||||
export const TYPE_HIGHSHELF = 2;
|
||||
export const TYPE_LOWPASS = 3;
|
||||
export const TYPE_HIGHPASS = 4;
|
||||
export const TYPE_BANDPASS = 5;
|
||||
export const TYPE_NOTCH = 6;
|
||||
export const TYPE_ALLPASS = 7;
|
||||
export const LPF_1ST = 8;
|
||||
|
||||
|
||||
|
||||
// Audio bean
|
||||
export class AudioBean {
|
||||
constructor(gain, fc, fs, type, bypass, q) {
|
||||
this.gain = gain;
|
||||
this.fc = fc;
|
||||
this.fs = fs;
|
||||
this.type = type;
|
||||
this.bypass = bypass;
|
||||
this.q = q;
|
||||
}
|
||||
|
||||
getGain(){return this.gain;}
|
||||
getFc(){return this.fc;}
|
||||
getFs(){return this.fs;}
|
||||
getType(){return this.type;}
|
||||
getBypass(){return this.bypass;}
|
||||
getQ(){return this.q;}
|
||||
setGain(gain){this.gain = gain;}
|
||||
setFc(fc){this.fc = fc;}
|
||||
setFs(fs){this.fs = fs;}
|
||||
setType(type){this.type = type;}
|
||||
setBypass(bypass){this.bypass = bypass;}
|
||||
setQ(q){this.q = q;}
|
||||
|
||||
toString(){
|
||||
return "AudioTunningEQ [gain=" + this.gain + ", fc=" + this.fc + ", fs=" + this.fs + ", type=" + this.type + ", bypass=" + this.bypass + ", q=" + this.q + "]";
|
||||
}
|
||||
}
|
||||
//Coeff bean
|
||||
class Coeff {
|
||||
constructor(props) {
|
||||
this.b0 = 0;
|
||||
this.b1 = 0;
|
||||
this.b2 = 0;
|
||||
this.a0 = 0;
|
||||
this.a1 = 0;
|
||||
this.a2 = 0;
|
||||
|
||||
}
|
||||
|
||||
setB0(b0) {this.b0 = b0;}
|
||||
setB1(b1) {this.b1 = b1;}
|
||||
setB2(b2) {this.b2 = b2;}
|
||||
setA0(a0) {this.a0 = a0;}
|
||||
setA1(a1) {this.a1 = a1;}
|
||||
setA2(a2) {this.a2 = a2;}
|
||||
getB0(){return this.b0;}
|
||||
getB1(){return this.b1;}
|
||||
getB2(){return this.b2;}
|
||||
getA0(){return this.a0;}
|
||||
getA1(){return this.a1;}
|
||||
getA2(){return this.a2;}
|
||||
|
||||
toString() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Complex bean
|
||||
class Complex {
|
||||
constructor(real, image) {
|
||||
this.real = real;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
getReal() {return this.real;}
|
||||
getImage() {return this.image;}
|
||||
setReal(real) {this.real = real;}
|
||||
setImage(image) {this.image = image;}
|
||||
|
||||
add(a) {
|
||||
return new Complex(this.real + a.real, this.image + a.image);
|
||||
}
|
||||
|
||||
sub(a) { // 复数相减
|
||||
return new Complex(this.real - a.real, this.image - a.image);
|
||||
}
|
||||
|
||||
div(a) { // 复数相除
|
||||
const denominator = a.real * a.real + a.image * a.image;
|
||||
const newReal = (this.real * a.real + this.image * a.image) / denominator;
|
||||
const newImage = (this.image * a.real - this.real * a.image) / denominator;
|
||||
return new Complex(newReal, newImage);
|
||||
}
|
||||
|
||||
mul(a) { // 复数相乘
|
||||
const newReal = this.real * a.real - this.image * a.image;
|
||||
const newImage = this.image * a.real + this.real * a.image;
|
||||
return new Complex(newReal, newImage);
|
||||
}
|
||||
|
||||
mulScalar(a) { // 复数与实数相乘
|
||||
return new Complex(this.real * a, this.image * a);
|
||||
}
|
||||
|
||||
addScalar(a) { // 复数与实数相加
|
||||
return new Complex(this.real + a, this.image);
|
||||
}
|
||||
}
|
||||
|
||||
function getFreqznList(coeffList, fs, f) {
|
||||
let n = f.length;
|
||||
let h = new Array(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
let w = 2*Math.PI*(f[i])/fs;
|
||||
let complex = getFreqwList(coeffList, w);
|
||||
h[i] = 20*Math.log10(Math.abs(getAmplitude(complex)));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
function getFreqzn(coeff, fs, f) {
|
||||
let n = f.length;
|
||||
let h = new Array(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
let w = 2*Math.PI*(f[i])/fs;
|
||||
let complex = getFreqw(coeff, w);
|
||||
h[i] = 20*Math.log10(Math.abs(getAmplitude(complex)));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
function getAmplitude(complex) {
|
||||
return Math.sqrt(Math.pow(complex.getReal(),2)+Math.pow(complex.getImage(),2));
|
||||
}
|
||||
|
||||
function getFreqw(coeff, w) {
|
||||
const complex = new Complex(Math.cos(w), -Math.sin(w));
|
||||
const b2 = (complex.mul(complex)).mulScalar(coeff.getB2());
|
||||
const b1 = complex.mulScalar(coeff.getB1());
|
||||
const hup = b2.add(b1).addScalar(coeff.getB0());
|
||||
const a2 = (complex.mul(complex)).mulScalar(coeff.getA2());
|
||||
const a1 = complex.mulScalar(coeff.getA1());
|
||||
const hdown = a2.add(a1).addScalar(coeff.getA0());
|
||||
return hup.div(hdown);
|
||||
}
|
||||
|
||||
function getFreqwList(coeffList, w){
|
||||
let h = getFreqw(coeffList[0], w);
|
||||
coeffList.slice(1).forEach((item) => {
|
||||
h = h.mul(getFreqw(item, w));
|
||||
});
|
||||
return h;
|
||||
}
|
||||
|
||||
function test(fc, q) {
|
||||
let w = fc * 2 / (48000*1000);
|
||||
let down = Math.sqrt(Math.pow((1 - w * w), 2) + w * w / (q * q));
|
||||
let gain = 1 / down;
|
||||
let db = 20 * Math.log10(gain);
|
||||
return db;
|
||||
}
|
||||
|
||||
export function visualizeResponse(coeffList, fs) {
|
||||
let validCoeffList = []
|
||||
let n = 349
|
||||
let startF = 20
|
||||
let endF = 20000
|
||||
let logStep = (Math.log10(20000) - Math.log10(20)) / n
|
||||
let f = new Array(n)
|
||||
let step = Math.pow(10, logStep)
|
||||
for (let i = 0; i < n; i++) {
|
||||
f[i] = startF * Math.pow(step, i)
|
||||
}
|
||||
|
||||
let semilogf = new Array(n)
|
||||
// 注意:此函数逻辑不能改动,保持与原项目一致,仅计算前 200 个点
|
||||
for (let i = 0; i < 200; i++) {
|
||||
semilogf[i] = Math.log10(f[i])
|
||||
}
|
||||
|
||||
let xValues = []
|
||||
let yValues = []
|
||||
let titleList = []
|
||||
coeffList.forEach((coeff, i) => {
|
||||
if (
|
||||
!Number.isNaN(coeff.getB0()) &&
|
||||
!Number.isNaN(coeff.getB1()) &&
|
||||
!Number.isNaN(coeff.getB2()) &&
|
||||
!Number.isNaN(coeff.getA0()) &&
|
||||
!Number.isNaN(coeff.getA1()) &&
|
||||
!Number.isNaN(coeff.getA2())
|
||||
) {
|
||||
validCoeffList.push(coeff)
|
||||
let h = getFreqzn(coeff, fs, f)
|
||||
xValues.push(semilogf)
|
||||
yValues.push(h)
|
||||
titleList.push('Band' + i)
|
||||
}
|
||||
})
|
||||
|
||||
if (yValues.length > 1) {
|
||||
let overall = getFreqznList(validCoeffList, fs, f)
|
||||
xValues.push(semilogf)
|
||||
yValues.push(overall)
|
||||
titleList.push('overall')
|
||||
}
|
||||
|
||||
let testArray = new Array(n)
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
testArray[i] = test(f[i], 1)
|
||||
}
|
||||
return [xValues[xValues.length - 1], yValues[yValues.length - 1]]
|
||||
}
|
||||
|
||||
export function getSectionsMatrix(gain, fc, q, type, bypass, fs) {
|
||||
let w = 2*fc/fs;
|
||||
let bypassStatus = bypass ? 1 : 0;
|
||||
let bqtype = type + bypassStatus * 10;
|
||||
const sA = Math.pow(10, gain / 40);
|
||||
const sqrt_sA = Math.sqrt(sA);
|
||||
const sin_w = Math.sin(Math.PI * w);
|
||||
const cos_w = Math.cos(Math.PI * w);
|
||||
const alpha = sin_w / (2*q);
|
||||
let b0, b1, b2, a0, a1, a2;
|
||||
switch (bqtype){
|
||||
case TYPE_PEAK:
|
||||
b0 = 1 + alpha * sA;
|
||||
b1 = -2 * cos_w;
|
||||
b2 = 1 - alpha * sA;
|
||||
a0 = 1 + alpha / sA;
|
||||
a1 = b1;
|
||||
a2 = 1 - alpha / sA;
|
||||
break;
|
||||
case TYPE_LOWSHELF:
|
||||
b0 = sA * ((sA + 1) - (sA - 1) * cos_w + 2 * sqrt_sA * alpha);
|
||||
b1 = 2 * sA * ((sA - 1) - (sA + 1) * cos_w);
|
||||
b2 = sA * ((sA + 1) - (sA - 1) * cos_w - 2 * sqrt_sA * alpha);
|
||||
a0 = (sA + 1) + (sA - 1) * cos_w + 2 * sqrt_sA * alpha;
|
||||
a1 = -2 * ((sA - 1) + (sA + 1) * cos_w);
|
||||
a2 = (sA + 1) + (sA - 1) * cos_w - 2 * sqrt_sA * alpha;
|
||||
break;
|
||||
case TYPE_HIGHSHELF:
|
||||
b0 = sA * ((sA + 1) + (sA - 1) * cos_w + 2 * sqrt_sA * alpha);
|
||||
b1 = -2 * sA * ((sA - 1) + (sA + 1) * cos_w);
|
||||
b2 = sA * ((sA + 1) + (sA - 1) * cos_w - 2 * sqrt_sA * alpha);
|
||||
a0 = (sA + 1) - (sA - 1) * cos_w + 2 * sqrt_sA * alpha;
|
||||
a1 = 2 * ((sA - 1) - (sA + 1) * cos_w);
|
||||
a2 = (sA + 1) - (sA - 1) * cos_w - 2 * sqrt_sA * alpha;
|
||||
break;
|
||||
case TYPE_LOWPASS:
|
||||
b0 = (1 - cos_w) / 2;
|
||||
b1 = 1 - cos_w;
|
||||
b2 = b0;
|
||||
a0 = 1 + alpha;
|
||||
a1 = -2 * cos_w;
|
||||
a2 = 1 - alpha;
|
||||
break;
|
||||
case TYPE_HIGHPASS:
|
||||
b0 = (1 + cos_w) / 2;
|
||||
b1 = -(1 + cos_w);
|
||||
b2 = b0;
|
||||
a0 = 1 + alpha;
|
||||
a1 = -2 * cos_w;
|
||||
a2 = 1 - alpha;
|
||||
break;
|
||||
case TYPE_BANDPASS:
|
||||
b0 = alpha;
|
||||
b1 = 0;
|
||||
b2 = -alpha;
|
||||
a0 = 1 + alpha;
|
||||
a1 = -2 * cos_w;
|
||||
a2 = 1 - alpha;
|
||||
break;
|
||||
case TYPE_NOTCH:
|
||||
b0 = 1;
|
||||
b1 = -2 * cos_w;
|
||||
b2 = 1;
|
||||
a0 = 1 + alpha;
|
||||
a1 = -2 * cos_w;
|
||||
a2 = 1 - alpha;
|
||||
break;
|
||||
case TYPE_ALLPASS:
|
||||
b0 = 1 - alpha;
|
||||
b1 = -2 * cos_w;
|
||||
b2 = 1 + alpha;
|
||||
a0 = b2;
|
||||
a1 = b1;
|
||||
a2 = b0;
|
||||
break;
|
||||
case LPF_1ST:
|
||||
let alpha_1st = sin_w / (cos_w + 1);
|
||||
b0 = alpha_1st / (1 + alpha_1st);
|
||||
b1 = b0;
|
||||
b2 = 0;
|
||||
a0 = 1;
|
||||
a1 = (alpha_1st - 1) / (1 + alpha_1st);
|
||||
a2 = 0;
|
||||
break;
|
||||
default:
|
||||
b0 = 1;
|
||||
b1 = 0;
|
||||
b2 = 0;
|
||||
a0 = 1;
|
||||
a1 = 0;
|
||||
a2 = 0;
|
||||
break;
|
||||
}
|
||||
let coeff = new Coeff();
|
||||
coeff.setB0(b0/a0);
|
||||
coeff.setB1(b1/a0);
|
||||
coeff.setB2(b2/a0);
|
||||
coeff.setA0(a0/a0);
|
||||
coeff.setA1(a1/a0);
|
||||
coeff.setA2(a2/a0);
|
||||
return coeff;
|
||||
}
|
||||
|
||||
export function getFilterShortName(type){
|
||||
switch (type){
|
||||
case "LOW_PASS": return "LPF";
|
||||
case "HIGH_PASS": return "HPF";
|
||||
case "BAND_PASS": return "BPF";
|
||||
case "LOW_SHELF": return "LSHELF";
|
||||
case "HIGH_SHELF": return "HSHELF";
|
||||
case "ALL_PASS": return "APF";
|
||||
case "PEAKING": return "PEAK";
|
||||
default: return type;
|
||||
}
|
||||
}
|
||||
|
||||
function getFilterTypeName(val){
|
||||
switch(val){
|
||||
case TYPE_LOWPASS: return "LPF";
|
||||
case TYPE_HIGHPASS: return "HPF";
|
||||
case TYPE_BANDPASS: return "BPF";
|
||||
case TYPE_NOTCH: return "NOTCH";
|
||||
case TYPE_PEAK: return "PEAK";
|
||||
case TYPE_LOWSHELF: return "LSHELF";
|
||||
case TYPE_HIGHSHELF: return "HSHELF";
|
||||
case TYPE_ALLPASS: return "APF";
|
||||
}
|
||||
}
|
||||
|
||||
export function getFilterType(typeName) {
|
||||
if(typeName === 'LPF' || typeName === 'LOWP_ASS'){
|
||||
return TYPE_LOWPASS;
|
||||
}
|
||||
else if(typeName === 'HPF' || typeName === 'HIGH_PASS'){
|
||||
return TYPE_HIGHPASS;
|
||||
}
|
||||
else if(typeName === 'BPF' || typeName === 'BAND_PASS'){
|
||||
return TYPE_BANDPASS;
|
||||
}
|
||||
else if(typeName === 'NOTCH'){
|
||||
return TYPE_NOTCH;
|
||||
}
|
||||
else if(typeName === 'PEAK' || typeName === 'PEAKING'){
|
||||
return TYPE_PEAK;
|
||||
}
|
||||
else if(typeName === 'LSHELF' || typeName === 'LOW_SHELF'){
|
||||
return TYPE_LOWSHELF;
|
||||
}
|
||||
else if(typeName === 'HSHELF' || typeName === 'HIGH_SHELF'){
|
||||
return TYPE_HIGHSHELF;
|
||||
}
|
||||
else if(typeName === 'APF' || typeName === 'ALL_PASS'){
|
||||
return TYPE_ALLPASS;
|
||||
}
|
||||
}
|
||||
|
||||
export function getChartOps(dataSet, yMax, yMin, lineColor) {
|
||||
//要显示的x轴刻度
|
||||
const labelsToShow = [0, 43, 85, 116, 160, 200, 233, 281, 320, 348]
|
||||
|
||||
return {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: dataSet[0],
|
||||
axisLabel: {
|
||||
formatter: function (value, index) {
|
||||
// 指定只显示 index 在(0,47,93,115)的标签
|
||||
if (labelsToShow.includes(index)) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return '20'
|
||||
case 43:
|
||||
return '50'
|
||||
case 85:
|
||||
return '100'
|
||||
case 116:
|
||||
return '200'
|
||||
case 160:
|
||||
return '500'
|
||||
case 200:
|
||||
return '1K'
|
||||
case 233:
|
||||
return '2K'
|
||||
case 281:
|
||||
return '5K'
|
||||
case 320:
|
||||
return '10K'
|
||||
case 348:
|
||||
return '20K'
|
||||
}
|
||||
}
|
||||
},
|
||||
interval: function (index) {
|
||||
return labelsToShow.includes(index)
|
||||
},
|
||||
fontSize: 14,
|
||||
color: '#999'
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#3A4348'
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#3A4348'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: yMin,
|
||||
max: yMax,
|
||||
interval: 5,
|
||||
|
||||
axisLabel: {
|
||||
fontSize: 14,
|
||||
color: '#999'
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#3A4348'
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#3A4348'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
top: 15,
|
||||
data: [
|
||||
{
|
||||
name: 'Equalizer',
|
||||
icon: 'circle',
|
||||
textStyle: { color: lineColor }, // 单独设置颜色
|
||||
itemStyle: {
|
||||
color: lineColor, // 设置图标颜色
|
||||
borderColor: lineColor // 如果需要边框
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Raw',
|
||||
icon: 'circle',
|
||||
textStyle: { color: '#ffffff' },
|
||||
itemStyle: {
|
||||
color: '#ffffff', // 设置图标颜色
|
||||
borderColor: '#ffffff' // 如果需要边框
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Equalized',
|
||||
icon: 'circle',
|
||||
textStyle: { color: '#23d2fe' },
|
||||
itemStyle: {
|
||||
color: '#23d2fe', // 设置图标颜色
|
||||
borderColor: '#23d2fe' // 如果需要边框
|
||||
}
|
||||
}
|
||||
],
|
||||
textStyle: {
|
||||
fontSize: 13
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Equalizer',
|
||||
data: dataSet[1],
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
color: lineColor
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#578400' },
|
||||
{
|
||||
offset: 1,
|
||||
color: '#578400'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import { base64DecodedToString, base64Encoded, PEQAPI, setProperty, UPGRADEPEQ } from '@/api/common.js'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import {
|
||||
AudioBean,
|
||||
getChartOps,
|
||||
getFilterType,
|
||||
getSectionsMatrix,
|
||||
visualizeResponse
|
||||
} from '@/api/audio.js'
|
||||
import * as echarts from 'echarts'
|
||||
import { i18n } from '@/main.js'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
export const getPeqData = async () => {
|
||||
const peqItems = ref([])
|
||||
const peqSelect = ref(0)
|
||||
const resp = await axios.get(PEQAPI)
|
||||
const peqEnable = ref(0)
|
||||
const msgCount = ref(0);
|
||||
const data = JSON.parse(base64DecodedToString(resp.data));
|
||||
|
||||
console.log('peq 数据=', data);
|
||||
if(data.peq.length > 0){
|
||||
data.peq.forEach((item, index) => {
|
||||
item['index'] = index
|
||||
item['filters'] = JSON.parse(item.filters)
|
||||
})
|
||||
peqItems.value = data.peq
|
||||
peqSelect.value = data.peqSelect
|
||||
}
|
||||
peqEnable.value = data.peqEnable
|
||||
msgCount.value = data.msgCount
|
||||
return {
|
||||
peqItems,
|
||||
peqSelect,
|
||||
peqEnable,
|
||||
msgCount
|
||||
}
|
||||
}
|
||||
|
||||
export function changePeq(val, peqItems) {
|
||||
setProperty('peqSelect', val)
|
||||
|
||||
const selectedItem = peqItems.find((item) => item.index === val)
|
||||
if (selectedItem) {
|
||||
console.log('选中了:' + selectedItem.name + ' filters = ' + selectedItem.filters)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const renderCharts = (peq, raw, changeParam) => {
|
||||
const list = []
|
||||
const fs = 48000
|
||||
peq.filters.forEach((item) => {
|
||||
const bean = new AudioBean(item.gain, item.fc, fs, getFilterType(item.type), false, item.q)
|
||||
list.push(
|
||||
getSectionsMatrix(
|
||||
bean.getGain(),
|
||||
bean.getFc(),
|
||||
bean.getQ(),
|
||||
bean.getType(),
|
||||
bean.getBypass(),
|
||||
bean.getFs()
|
||||
)
|
||||
)
|
||||
})
|
||||
const dataSet = visualizeResponse(list, fs)
|
||||
const ops = getChartOps(dataSet, 20, -20, '#FFED00')
|
||||
|
||||
// 统一获取DOM元素
|
||||
const chartDom = document.getElementById('main')
|
||||
|
||||
// 尝试获取已存在的实例
|
||||
let myChart = echarts.getInstanceByDom(chartDom)
|
||||
|
||||
// 如果实例不存在,则初始化
|
||||
if (!myChart) {
|
||||
myChart = echarts.init(chartDom)
|
||||
}
|
||||
|
||||
if (changeParam && myChart) {
|
||||
// 只有在changeParam为true且图表存在时才获取原始数据
|
||||
raw = myChart.getOption().series[1].data
|
||||
}
|
||||
|
||||
// 不再重新初始化,直接使用现有的myChart实例
|
||||
myChart.clear()
|
||||
|
||||
if (raw) {
|
||||
ops.series.push({
|
||||
name: 'Raw',
|
||||
data: raw,
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
color: '#ffffff'
|
||||
}
|
||||
})
|
||||
|
||||
const equalized_raw = dataSet[1].map((value, index) => value + raw[index])
|
||||
ops.series.push({
|
||||
name: 'Equalized',
|
||||
data: equalized_raw,
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
color: '#23d2fe',
|
||||
width: 6,
|
||||
opacity: 0.7
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
myChart.setOption(ops, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换auto开关
|
||||
* @param peq
|
||||
*/
|
||||
export const upgradeAutoPre = (peq, autoPre) => {
|
||||
const filters = peq.filters.map((item) => ({
|
||||
type: getFilterVal(item.type),
|
||||
fc: item.fc,
|
||||
gain: item.gain,
|
||||
q: item.q
|
||||
}))
|
||||
const data = {
|
||||
peqChange: {
|
||||
name: peq.name,
|
||||
filters: filters,
|
||||
autoPre: autoPre ? 1 : 0,
|
||||
preamp: peq.preamp,
|
||||
canDel: peq.canDel
|
||||
}
|
||||
}
|
||||
upgradePeq(data)
|
||||
peq.autoPre = autoPre ? 1 : 0
|
||||
}
|
||||
|
||||
//修改总增益
|
||||
export const upgradePreamp = (peq, preamp) => {
|
||||
const filters = peq.filters.map((item) => ({
|
||||
type: getFilterVal(item.type),
|
||||
fc: item.fc,
|
||||
gain: item.gain,
|
||||
q: item.q
|
||||
}))
|
||||
const data = {
|
||||
peqChange: {
|
||||
name: peq.name,
|
||||
filters: filters,
|
||||
autoPre: peq.autoPre,
|
||||
preamp: preamp,
|
||||
canDel: peq.canDel
|
||||
}
|
||||
}
|
||||
upgradePeq(data)
|
||||
|
||||
peq.preamp = preamp
|
||||
}
|
||||
|
||||
export const upgradeEdit = (peq) => {
|
||||
const filters = peq.filters.map((item) => ({
|
||||
type: getFilterVal(item.type),
|
||||
fc: item.fc,
|
||||
gain: item.gain,
|
||||
q: item.q
|
||||
}))
|
||||
const data = {
|
||||
peqChange: {
|
||||
name: peq.name,
|
||||
filters: filters,
|
||||
autoPre: peq.autoPre,
|
||||
preamp: peq.preamp,
|
||||
canDel: peq.canDel
|
||||
}
|
||||
}
|
||||
upgradePeq(data)
|
||||
}
|
||||
|
||||
//这里有个问题,当接口超时时,由于代码是同步,所以会一直阻塞等待
|
||||
export const upgradePeq = async (peq) => {
|
||||
await axios.post(
|
||||
UPGRADEPEQ,
|
||||
{ json: base64Encoded(JSON.stringify(peq)) },
|
||||
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }
|
||||
)
|
||||
}
|
||||
|
||||
export const getFilterVal = (filterName) => {
|
||||
let result = -1
|
||||
if (filterName === 'HIGH_PASS' || filterName === 'HPF') {
|
||||
result = 1
|
||||
} else if (filterName === 'BAND_PASS' || filterName === 'BPF') {
|
||||
result = 2
|
||||
} else if (filterName === 'NOTCH') {
|
||||
result = 3
|
||||
} else if (filterName === 'PEAKING' || filterName === 'PEAK') {
|
||||
result = 4
|
||||
} else if (filterName === 'LOW_SHELF' || filterName === 'LSHELF') {
|
||||
result = 5
|
||||
} else if (filterName === 'HIGH_SHELF' || filterName === 'HSHELF') {
|
||||
result = 6
|
||||
} else if (filterName === 'ALL_PASS' || filterName === 'APF') {
|
||||
result = 7
|
||||
} else if (filterName === 'LOW_PASS' || filterName === 'LPF') {
|
||||
result = 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变滤波器的属性(频率,gain,q, 类型)
|
||||
* @param currentFilter 当前选中的滤波器
|
||||
* @param val 值
|
||||
*/
|
||||
export const changeFilterVal = (currentFilter, val, name, peq) => {
|
||||
//currentFilter !== undefined 表示当前有某一个滤波器被选中,才需要更新下面的值
|
||||
if (currentFilter !== undefined) {
|
||||
if (name === 'freq') {
|
||||
currentFilter.fc = val
|
||||
} else if (name === 'gain') {
|
||||
currentFilter.gain = val
|
||||
} else if (name === 'q') {
|
||||
currentFilter.q = val
|
||||
} else if (name === 'type') {
|
||||
currentFilter.type = val
|
||||
}
|
||||
|
||||
//调用接口,更新peq
|
||||
//需要将滤波器类型转换为数字,因为是引用类型,所以这里还需要遍历filters,声明新的filters,将值传过去,不能直接用peq.filters
|
||||
const filters = peq.filters.map((item) => ({
|
||||
type: getFilterVal(item.type),
|
||||
fc: item.fc,
|
||||
gain: item.gain,
|
||||
q: item.q
|
||||
}))
|
||||
|
||||
const data = {
|
||||
peqChange: {
|
||||
name: peq.name,
|
||||
filters: filters,
|
||||
autoPre: peq.autoPre,
|
||||
preamp: peq.preamp,
|
||||
canDel: peq.canDel
|
||||
}
|
||||
}
|
||||
upgradePeq(data)
|
||||
renderCharts(peq)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染添加耳机型号窗口数据
|
||||
*/
|
||||
export const renderAddHeadPhone = () => {
|
||||
const menus = [
|
||||
{ value: 'Brands', label: 'Brands' },
|
||||
{ value: 'Models', label: 'Models' },
|
||||
{ value: 'Target', label: 'Target' }
|
||||
]
|
||||
const selectedMenu = ref('Brands')
|
||||
const targetList = ref([
|
||||
{ name: 'Harman over-ear 2018', bassBoost: { fc: 105, q: 0.7, gain: 6 } , ear: 'over'},
|
||||
{ name: 'HMS II.3 Harman over-ear 2018', bassBoost: { fc: 105, q: 0.7, gain: 6 }, ear: 'over'},
|
||||
{ name: 'crinacle EARS + 711 Harman over-ear 2018', bassBoost: { fc: 105, q: 0.7, gain: 6 } , ear: 'over'},
|
||||
{ name: 'Harman in-ear 2019', bassBoost: { fc: 105, q: 0.7, gain: 9.5 } ,ear: 'in'},
|
||||
{ name: 'AutoEq in-ear', bassBoost: { fc: 105, q: 0.7, gain: 8 }, ear: 'in'},
|
||||
{ name: 'HMS II.3 AutoEq in-ear', bassBoost: { fc: 105, q: 0.7, gain: 8 } ,ear: 'in'},
|
||||
{ name: 'HMS II.3 Harman in-ear 2019', bassBoost: { fc: 105, q: 0.7, gain: 9.5 } ,ear: 'in'},
|
||||
{ name: 'Diffuse Field 5128 (-1 dB/oct)', bassBoost: { fc: 105, q: 0.7, gain: 0 }, ear: 'over'},
|
||||
{ name: 'LMG 5128 0.6 without bass', bassBoost: { fc: 105, q: 0.7, gain: 6 } ,ear: 'over'},
|
||||
{ name: 'JM-1 with Harman filters', bassBoost: { fc: 105, q: 0.7, gain: 6.5 } ,ear: 'all'},
|
||||
{ name: 'oratory1990 in-ear', bassBoost: { fc: 105, q: 0.7, gain: 9.5 } ,ear: 'in'},
|
||||
{ name: 'oratory1990 over-ear', bassBoost: { fc: 105, q: 0.7, gain: 6 } ,ear: 'over'},
|
||||
{ name: 'Harman over-ear 2013', bassBoost: { fc: 105, q: 0.7, gain: 6 } ,ear: 'over'},
|
||||
{ name: 'Flat', bassBoost: { fc: 105, q: 0.7, gain: 0 } ,ear: 'all'}
|
||||
]);
|
||||
return { menus, selectedMenu, targetList }
|
||||
}
|
||||
|
||||
export const getCurve = async (brand, name, target) =>{
|
||||
const resp = await axios.get('//api.luxsin.com.cn/audio/getCurve?brand='+encodeURIComponent(brand)+'&name='+encodeURIComponent(name)+'&target='+encodeURIComponent(target));
|
||||
const data = JSON.parse(base64DecodedToString(resp.data));
|
||||
|
||||
if(data.hasOwnProperty('parametric_eq')) {
|
||||
return data.parametric_eq;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getModelCurve = async (brand, name) => {
|
||||
const resp = await axios.get(
|
||||
'//api.luxsin.com.cn/audio/modelCurve?brand=' +
|
||||
encodeURIComponent(brand) +
|
||||
'&name=' +
|
||||
encodeURIComponent(name)
|
||||
)
|
||||
const data = JSON.parse(base64DecodedToString(resp.data))
|
||||
console.log('型号的原始数据:', data)
|
||||
if (data.hasOwnProperty('fr')) {
|
||||
return data.fr
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export const msg = (context) => {
|
||||
ElMessageBox.alert(context, i18n.global.t('prompt.prompt'), {
|
||||
confirmButtonText: i18n.global.t('prompt.confirm')
|
||||
})
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@
|
||||
============================================================ */
|
||||
import { useDevice } from "@/contexts/DeviceContext";
|
||||
import { cn } from "@/lib/utils";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
import { useLocation } from "wouter";
|
||||
|
||||
@@ -138,6 +139,7 @@ export default function IOPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BottomNav />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
============================================================ */
|
||||
import { useDevice } from "@/contexts/DeviceContext";
|
||||
import { cn } from "@/lib/utils";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import { Check, ChevronLeft } from "lucide-react";
|
||||
import { useLocation } from "wouter";
|
||||
|
||||
@@ -83,6 +84,7 @@ export default function VUPage() {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<BottomNav />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user