فهرست منبع

Merge branch 'ktyq-online-1.8.7' of http://git.dayaedu.com/liushengqiang/music-score into hqyDevNewVersion

黄琪勇 1 سال پیش
والد
کامیت
553aa2664e
66فایلهای تغییر یافته به همراه534 افزوده شده و 99 حذف شده
  1. 8 8
      dist/colexiu.html
  2. 0 0
      dist/css/index-33f3c513.css
  3. 10 10
      dist/index.html
  4. 8 8
      dist/instrument.html
  5. 0 0
      dist/js/colexiu-4a63d64c.js
  6. 0 0
      dist/js/colexiu-852bf948.js
  7. 0 0
      dist/js/colexiu-legacy-9355aa1b.js
  8. 0 0
      dist/js/gym-65bdffe8.js
  9. 0 0
      dist/js/gym-b9cd6dfb.js
  10. 0 0
      dist/js/gym-legacy-d01e3f3a.js
  11. 0 0
      dist/js/gym-legacy-d67a9763.js
  12. 0 0
      dist/js/index-27021a09.js
  13. 0 0
      dist/js/index-56f64eda.js
  14. 0 0
      dist/js/index-64ed09c7.js
  15. 0 0
      dist/js/index-666ce298.js
  16. 0 1
      dist/js/index-6e1cda05.js
  17. 1 0
      dist/js/index-948cb66f.js
  18. 1 0
      dist/js/index-97f5c368.js
  19. 0 0
      dist/js/index-b9ef8792.js
  20. 0 0
      dist/js/index-c2089ca3.js
  21. 0 0
      dist/js/index-c987494a.js
  22. 1 1
      dist/js/index-d8f93bbd.js
  23. 0 0
      dist/js/index-legacy-0d39e819.js
  24. 1 1
      dist/js/index-legacy-14119fee.js
  25. 0 0
      dist/js/index-legacy-2c10c9fd.js
  26. 1 1
      dist/js/index-legacy-372dec40.js
  27. 0 0
      dist/js/index-legacy-6e0674c9.js
  28. 0 0
      dist/js/index-legacy-97c843b5.js
  29. 1 0
      dist/js/index-legacy-b0a6e4c1.js
  30. 0 0
      dist/js/index-legacy-c1565b73.js
  31. 0 0
      dist/js/index-legacy-c75c42f0.js
  32. 0 0
      dist/js/index-legacy-ffc51b77.js
  33. 0 0
      dist/js/instrument-b8fe6d59.js
  34. 0 0
      dist/js/instrument-ff82a3ab.js
  35. 0 0
      dist/js/instrument-legacy-6acd9b82.js
  36. 0 0
      dist/js/instrument-legacy-ecdaefc3.js
  37. 0 0
      dist/js/orchestra-510ca9a9.js
  38. 0 0
      dist/js/orchestra-9b200011.js
  39. 0 0
      dist/js/orchestra-legacy-4ed40420.js
  40. 0 0
      dist/js/orchestra-legacy-5f41c20f.js
  41. 0 0
      dist/js/polyfills-1a2e4f1c.js
  42. 0 0
      dist/js/polyfills-legacy-b3b6467d.js
  43. 0 0
      dist/js/report-share-ef089666.js
  44. 0 0
      dist/js/report-share-legacy-1420c584.js
  45. 9 9
      dist/orchestra.html
  46. 6 6
      dist/report-share.html
  47. BIN
      dist/wav/tick-7706b760.wav
  48. BIN
      dist/wav/tock-32d5f74b.wav
  49. BIN
      src/assets/tick.mp3
  50. BIN
      src/assets/tick.wav
  51. BIN
      src/assets/tock.mp3
  52. BIN
      src/assets/tock.wav
  53. 7 3
      src/helpers/metronome.ts
  54. 14 2
      src/page-instrument/header-top/index.tsx
  55. 3 2
      src/page-instrument/header-top/settting/index.tsx
  56. 3 2
      src/page-instrument/view-detail/index.tsx
  57. 17 1
      src/state.ts
  58. 196 0
      src/utils/crunker.ts
  59. BIN
      src/view/audio-list/img/icon_loading_head.png
  60. BIN
      src/view/audio-list/img/icon_loading_img.png
  61. 61 0
      src/view/audio-list/index.module.less
  62. 135 32
      src/view/audio-list/index.tsx
  63. 39 0
      src/view/audio-list/loading.tsx
  64. 11 11
      src/view/tick/index.tsx
  65. 0 0
      stats.html
  66. 1 1
      vite.config.ts

+ 8 - 8
dist/colexiu.html

@@ -2,7 +2,7 @@
 <html lang="en">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-fbd9978d.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-1a2e4f1c.js"></script>
 
   <meta charset="UTF-8" />
   <link rel="icon" type="image/svg+xml" href="./vite.svg" />
@@ -40,11 +40,11 @@
       },
     })
   </script>
-  <script type="module" crossorigin src="./js/colexiu-852bf948.js"></script>
-  <link rel="modulepreload" crossorigin href="./js/index-726208cc.js">
-  <link rel="modulepreload" crossorigin href="./js/index-0f12126a.js">
-  <link rel="modulepreload" crossorigin href="./js/index-a6bdcc2d.js">
-  <link rel="stylesheet" href="./css/index-3989851b.css">
+  <script type="module" crossorigin src="./js/colexiu-4a63d64c.js"></script>
+  <link rel="modulepreload" crossorigin href="./js/index-c987494a.js">
+  <link rel="modulepreload" crossorigin href="./js/index-d8f93bbd.js">
+  <link rel="modulepreload" crossorigin href="./js/index-666ce298.js">
+  <link rel="stylesheet" href="./css/index-33f3c513.css">
   <link rel="stylesheet" href="./css/index-d42b0794.css">
   <link rel="stylesheet" href="./css/colexiu-62f31c4f.css">
   <script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
@@ -56,8 +56,8 @@
   <img id="loading" class="show" src="./loading.svg" alt="loading" />
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-08e53fef.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/colexiu-legacy-7b382d9f.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b3b6467d.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/colexiu-legacy-9355aa1b.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/css/index-33f3c513.css


+ 10 - 10
dist/index.html

@@ -2,7 +2,7 @@
 <html lang="ZH-cn">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-fbd9978d.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-1a2e4f1c.js"></script>
 
   <meta charset="UTF-8">
   <link rel="icon" href="./favicon.ico" />
@@ -75,14 +75,14 @@
       }
     })
   </script>
-  <script type="module" crossorigin src="./js/gym-b9cd6dfb.js"></script>
-  <link rel="modulepreload" crossorigin href="./js/index-726208cc.js">
-  <link rel="modulepreload" crossorigin href="./js/index-64ed09c7.js">
-  <link rel="modulepreload" crossorigin href="./js/index-dddff9f0.js">
-  <link rel="modulepreload" crossorigin href="./js/index-0f12126a.js">
-  <link rel="modulepreload" crossorigin href="./js/index-a6bdcc2d.js">
+  <script type="module" crossorigin src="./js/gym-65bdffe8.js"></script>
+  <link rel="modulepreload" crossorigin href="./js/index-c987494a.js">
+  <link rel="modulepreload" crossorigin href="./js/index-948cb66f.js">
+  <link rel="modulepreload" crossorigin href="./js/index-27021a09.js">
+  <link rel="modulepreload" crossorigin href="./js/index-d8f93bbd.js">
+  <link rel="modulepreload" crossorigin href="./js/index-666ce298.js">
   <link rel="modulepreload" crossorigin href="./js/plyr.min-c8c2777b.js">
-  <link rel="stylesheet" href="./css/index-3989851b.css">
+  <link rel="stylesheet" href="./css/index-33f3c513.css">
   <link rel="stylesheet" href="./css/index-85f95688.css">
   <link rel="stylesheet" href="./css/index-d42b0794.css">
   <link rel="stylesheet" href="./css/plyr-ad8ef5ae.css">
@@ -100,8 +100,8 @@
   <img id="loading" class="show" src="./loading.svg" alt="loading" />
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-08e53fef.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/gym-legacy-d01e3f3a.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b3b6467d.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/gym-legacy-d67a9763.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 8 - 8
dist/instrument.html

@@ -2,7 +2,7 @@
 <html lang="en">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-fbd9978d.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-1a2e4f1c.js"></script>
 
   <meta charset="UTF-8" />
   <meta name="viewport"
@@ -40,11 +40,11 @@
       })
     }
   </script>
-  <script type="module" crossorigin src="./js/instrument-b8fe6d59.js"></script>
-  <link rel="modulepreload" crossorigin href="./js/index-726208cc.js">
-  <link rel="modulepreload" crossorigin href="./js/index-a6bdcc2d.js">
-  <link rel="modulepreload" crossorigin href="./js/index-64ed09c7.js">
-  <link rel="stylesheet" href="./css/index-3989851b.css">
+  <script type="module" crossorigin src="./js/instrument-ff82a3ab.js"></script>
+  <link rel="modulepreload" crossorigin href="./js/index-c987494a.js">
+  <link rel="modulepreload" crossorigin href="./js/index-666ce298.js">
+  <link rel="modulepreload" crossorigin href="./js/index-948cb66f.js">
+  <link rel="stylesheet" href="./css/index-33f3c513.css">
   <link rel="stylesheet" href="./css/index-d42b0794.css">
   <link rel="stylesheet" href="./css/instrument-d78850b6.css">
   <script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
@@ -64,8 +64,8 @@
 
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-08e53fef.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/instrument-legacy-ecdaefc3.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b3b6467d.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/instrument-legacy-6acd9b82.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/colexiu-4a63d64c.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/colexiu-852bf948.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/colexiu-legacy-9355aa1b.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/gym-65bdffe8.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/gym-b9cd6dfb.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/gym-legacy-d01e3f3a.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/gym-legacy-d67a9763.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-27021a09.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-56f64eda.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-64ed09c7.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-666ce298.js


+ 0 - 1
dist/js/index-6e1cda05.js

@@ -1 +0,0 @@
-import{d as i,g as l,n as d,cb as e,c,m as r,f as s,av as u}from"./index-726208cc.js";const f="_skeleton_vtlsh_1",m="_detail_vtlsh_12",p="_container_vtlsh_20",a={skeleton:f,detail:m,container:p},y=i({name:"music-list",setup(){const n=l(),t=d({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:e.staff,base64:""},{state:!1,name:"首调",type:e.firstTone,base64:""},{state:!1,name:"固定调",type:e.fixedTone,base64:""}]});c(()=>{window.appName="colexiu",r.xmlUrl=n.xmlUrl,t.isLoading=!1});const o=async()=>{console.log("渲染完成")};return()=>s("div",{class:a.detail},[s("div",{id:"scrollContainer",class:[a.container,"hideCursor"]},[!t.isLoading&&s(u,{onRendered:o},null)])])}});export{y as default};

+ 1 - 0
dist/js/index-948cb66f.js

@@ -0,0 +1 @@
+import{ba as w,c2 as C,bh as E,bg as L,d as B,l as h,c3 as R,c4 as N,w as b,c5 as _,c as y,c6 as F,c7 as G,f as r,aG as H,c8 as m,c9 as I,ca as M,bl as U}from"./index-c987494a.js";const[V,o,j]=w("list"),q={error:Boolean,offset:C(300),loading:Boolean,disabled:Boolean,finished:Boolean,errorText:String,direction:E("down"),loadingText:String,finishedText:String,immediateCheck:L};var z=B({name:V,props:q,emits:["load","update:error","update:loading"],setup(e,{emit:s,slots:a}){const d=h(e.loading),f=h(),g=h(),c=R(),v=N(f),n=()=>{H(()=>{if(d.value||e.finished||e.disabled||e.error||(c==null?void 0:c.value)===!1)return;const{direction:t}=e,l=+e.offset,i=m(v);if(!i.height||I(f))return;let u=!1;const x=m(g);t==="up"?u=i.top-x.top<=l:u=x.bottom-i.bottom<=l,u&&(d.value=!0,s("update:loading",!0),s("load"))})},T=()=>{if(e.finished){const t=a.finished?a.finished():e.finishedText;if(t)return r("div",{class:o("finished-text")},[t])}},k=()=>{s("update:error",!1),n()},P=()=>{if(e.error){const t=a.error?a.error():e.errorText;if(t)return r("div",{role:"button",class:o("error-text"),tabindex:0,onClick:k},[t])}},S=()=>{if(d.value&&!e.finished&&!e.disabled)return r("div",{class:o("loading")},[a.loading?a.loading():r(M,{class:o("loading-icon")},{default:()=>[e.loadingText||j("loading")]})])};return b(()=>[e.loading,e.finished,e.error],n),c&&b(c,t=>{t&&n()}),_(()=>{d.value=e.loading}),y(()=>{e.immediateCheck&&n()}),F({check:n}),G("scroll",n,{target:v,passive:!0}),()=>{var t;const l=(t=a.default)==null?void 0:t.call(a),i=r("div",{ref:g,class:o("placeholder")},null);return r("div",{ref:f,role:"feed",class:o(),"aria-busy":d.value},[e.direction==="down"?l:i,S(),T(),P(),e.direction==="up"?l:i])}}});const D=U(z);export{D as L};

+ 1 - 0
dist/js/index-97f5c368.js

@@ -0,0 +1 @@
+import{d as i,g as l,n as c,cc as e,c as d,m as r,f as s,aw as u}from"./index-c987494a.js";const f="_skeleton_vtlsh_1",m="_detail_vtlsh_12",p="_container_vtlsh_20",a={skeleton:f,detail:m,container:p},y=i({name:"music-list",setup(){const n=l(),t=c({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:e.staff,base64:""},{state:!1,name:"首调",type:e.firstTone,base64:""},{state:!1,name:"固定调",type:e.fixedTone,base64:""}]});d(()=>{window.appName="colexiu",r.xmlUrl=n.xmlUrl,t.isLoading=!1});const o=async()=>{console.log("渲染完成")};return()=>s("div",{class:a.detail},[s("div",{id:"scrollContainer",class:[a.container,"hideCursor"]},[!t.isLoading&&s(u,{onRendered:o},null)])])}});export{y as default};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-b9ef8792.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-c2089ca3.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-c987494a.js


+ 1 - 1
dist/js/index-0f12126a.js → dist/js/index-d8f93bbd.js

@@ -1 +1 @@
-import{d,l as i,n as p,m as e,w as o,f as r,U as a}from"./index-726208cc.js";const c=d({name:"measureSpeed",setup(){const s=i(!1),t=p({speed:e.speed,originSpeed:e.originSpeed});return o(()=>e.section.length,()=>{if(e.modeType==="practise"){if(!s.value&&e.section.length===2){s.value=!0,t.speed=e.speed;const n=e.section[0].beatSpeed;e.originSpeed=n,a(n)}s.value&&e.section.length===0&&(s.value=!1,e.originSpeed=t.originSpeed,a(t.speed))}}),()=>r("div",null,null)}});export{c as M};
+import{d,l as i,n as p,m as e,w as o,f as r,V as a}from"./index-c987494a.js";const c=d({name:"measureSpeed",setup(){const s=i(!1),t=p({speed:e.speed,originSpeed:e.originSpeed});return o(()=>e.section.length,()=>{if(e.modeType==="practise"){if(!s.value&&e.section.length===2){s.value=!0,t.speed=e.speed;const n=e.section[0].beatSpeed;e.originSpeed=n,a(n)}s.value&&e.section.length===0&&(s.value=!1,e.originSpeed=t.originSpeed,a(t.speed))}}),()=>r("div",null,null)}});export{c as M};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-0d39e819.js


+ 1 - 1
dist/js/index-legacy-62c1f845.js → dist/js/index-legacy-14119fee.js

@@ -1 +1 @@
-System.register(["./index-legacy-3c467273.js"],(function(e,t){"use strict";var i,n,a,o,r,s,d,l,c=document.createElement("style");return c.textContent="._skeleton_vtlsh_1{position:fixed;left:0;top:0;width:100vw;height:100vh;padding:.53333rem .8rem;background-color:#fff;z-index:1000;--van-skeleton-paragraph-height: .8rem}._detail_vtlsh_12{width:100vw;height:100vh;overflow:hidden;overflow-y:auto;--header-height: 1.65333rem;background:var(--container-background)}._detail_vtlsh_12 ._container_vtlsh_20{margin:0 .26667rem;border-radius:.26667rem}._detail_vtlsh_12 #musicAndSelection{overflow:initial!important;height:initial!important;max-height:initial!important}\n",document.head.appendChild(c),{setters:[e=>{i=e.d,n=e.g,a=e.n,o=e.cb,r=e.c,s=e.m,d=e.f,l=e.av}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=a({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:o.staff,base64:""},{state:!1,name:"首调",type:o.firstTone,base64:""},{state:!1,name:"固定调",type:o.fixedTone,base64:""}]});r((()=>{window.appName="colexiu",s.xmlUrl=e.xmlUrl,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>d("div",{class:t},[d("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&d(l,{onRendered:h},null)])])}}))}}}));
+System.register(["./index-legacy-c75c42f0.js"],(function(e,t){"use strict";var i,n,a,o,r,s,d,l,c=document.createElement("style");return c.textContent="._skeleton_vtlsh_1{position:fixed;left:0;top:0;width:100vw;height:100vh;padding:.53333rem .8rem;background-color:#fff;z-index:1000;--van-skeleton-paragraph-height: .8rem}._detail_vtlsh_12{width:100vw;height:100vh;overflow:hidden;overflow-y:auto;--header-height: 1.65333rem;background:var(--container-background)}._detail_vtlsh_12 ._container_vtlsh_20{margin:0 .26667rem;border-radius:.26667rem}._detail_vtlsh_12 #musicAndSelection{overflow:initial!important;height:initial!important;max-height:initial!important}\n",document.head.appendChild(c),{setters:[e=>{i=e.d,n=e.g,a=e.n,o=e.cc,r=e.c,s=e.m,d=e.f,l=e.aw}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=a({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:o.staff,base64:""},{state:!1,name:"首调",type:o.firstTone,base64:""},{state:!1,name:"固定调",type:o.fixedTone,base64:""}]});r((()=>{window.appName="colexiu",s.xmlUrl=e.xmlUrl,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>d("div",{class:t},[d("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&d(l,{onRendered:h},null)])])}}))}}}));

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-2c10c9fd.js


+ 1 - 1
dist/js/index-legacy-58e11036.js → dist/js/index-legacy-372dec40.js

@@ -1 +1 @@
-System.register(["./index-legacy-3c467273.js"],(function(e,n){"use strict";var i,t,s,d,r,p,o;return{setters:[e=>{i=e.d,t=e.l,s=e.n,d=e.m,r=e.w,p=e.f,o=e.U}],execute:function(){e("M",i({name:"measureSpeed",setup(){const e=t(!1),n=s({speed:d.speed,originSpeed:d.originSpeed});return r((()=>d.section.length),(()=>{if("practise"===d.modeType){if(!e.value&&2===d.section.length){e.value=!0,n.speed=d.speed;const i=d.section[0].beatSpeed;d.originSpeed=i,o(i)}e.value&&0===d.section.length&&(e.value=!1,d.originSpeed=n.originSpeed,o(n.speed))}})),()=>p("div",null,null)}}))}}}));
+System.register(["./index-legacy-c75c42f0.js"],(function(e,n){"use strict";var i,t,s,d,r,p,o;return{setters:[e=>{i=e.d,t=e.l,s=e.n,d=e.m,r=e.w,p=e.f,o=e.V}],execute:function(){e("M",i({name:"measureSpeed",setup(){const e=t(!1),n=s({speed:d.speed,originSpeed:d.originSpeed});return r((()=>d.section.length),(()=>{if("practise"===d.modeType){if(!e.value&&2===d.section.length){e.value=!0,n.speed=d.speed;const i=d.section[0].beatSpeed;d.originSpeed=i,o(i)}e.value&&0===d.section.length&&(e.value=!1,d.originSpeed=n.originSpeed,o(n.speed))}})),()=>p("div",null,null)}}))}}}));

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-6e0674c9.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-97c843b5.js


+ 1 - 0
dist/js/index-legacy-b0a6e4c1.js

@@ -0,0 +1 @@
+System.register(["./index-legacy-c75c42f0.js"],(function(e,i){"use strict";var r,t,o,n,a,d,l,s,c,u,f,g,h,v,p,b,x,m,T;return{setters:[e=>{r=e.ba,t=e.c2,o=e.bh,n=e.bg,a=e.d,d=e.l,l=e.c3,s=e.c4,c=e.w,u=e.c5,f=e.c,g=e.c6,h=e.c7,v=e.f,p=e.aG,b=e.c8,x=e.c9,m=e.ca,T=e.bl}],execute:function(){const[i,k,B]=r("list"),S={error:Boolean,offset:t(300),loading:Boolean,disabled:Boolean,finished:Boolean,errorText:String,direction:o("down"),loadingText:String,finishedText:String,immediateCheck:n};var w=a({name:i,props:S,emits:["load","update:error","update:loading"],setup(e,{emit:i,slots:r}){const t=d(e.loading),o=d(),n=d(),a=l(),T=s(o),S=()=>{p((()=>{if(t.value||e.finished||e.disabled||e.error||!1===(null==a?void 0:a.value))return;const{direction:r}=e,d=+e.offset,l=b(T);if(!l.height||x(o))return;let s=!1;const c=b(n);s="up"===r?l.top-c.top<=d:c.bottom-l.bottom<=d,s&&(t.value=!0,i("update:loading",!0),i("load"))}))},w=()=>{if(e.finished){const i=r.finished?r.finished():e.finishedText;if(i)return v("div",{class:k("finished-text")},[i])}},y=()=>{i("update:error",!1),S()},C=()=>{if(e.error){const i=r.error?r.error():e.errorText;if(i)return v("div",{role:"button",class:k("error-text"),tabindex:0,onClick:y},[i])}},j=()=>{if(t.value&&!e.finished&&!e.disabled)return v("div",{class:k("loading")},[r.loading?r.loading():v(m,{class:k("loading-icon")},{default:()=>[e.loadingText||B("loading")]})])};return c((()=>[e.loading,e.finished,e.error]),S),a&&c(a,(e=>{e&&S()})),u((()=>{t.value=e.loading})),f((()=>{e.immediateCheck&&S()})),g({check:S}),h("scroll",S,{target:T,passive:!0}),()=>{var i;const a=null==(i=r.default)?void 0:i.call(r),d=v("div",{ref:n,class:k("placeholder")},null);return v("div",{ref:o,role:"feed",class:k(),"aria-busy":t.value},["down"===e.direction?a:d,j(),w(),C(),"up"===e.direction?a:d])}}});e("L",T(w))}}}));

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-c1565b73.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-c75c42f0.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/index-legacy-ffc51b77.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/instrument-b8fe6d59.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/instrument-ff82a3ab.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/instrument-legacy-6acd9b82.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/instrument-legacy-ecdaefc3.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/orchestra-510ca9a9.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/orchestra-9b200011.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/orchestra-legacy-4ed40420.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/orchestra-legacy-5f41c20f.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/polyfills-1a2e4f1c.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/polyfills-legacy-b3b6467d.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/report-share-ef089666.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/report-share-legacy-1420c584.js


+ 9 - 9
dist/orchestra.html

@@ -2,7 +2,7 @@
 <html lang="en">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-fbd9978d.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-1a2e4f1c.js"></script>
 
   <meta charset="UTF-8" />
   <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
@@ -41,12 +41,12 @@
       transition: opacity .3s;
     }
   </style>
-  <script type="module" crossorigin src="./js/orchestra-510ca9a9.js"></script>
-  <link rel="modulepreload" crossorigin href="./js/index-726208cc.js">
-  <link rel="modulepreload" crossorigin href="./js/index-dddff9f0.js">
-  <link rel="modulepreload" crossorigin href="./js/index-0f12126a.js">
-  <link rel="modulepreload" crossorigin href="./js/index-a6bdcc2d.js">
-  <link rel="stylesheet" href="./css/index-3989851b.css">
+  <script type="module" crossorigin src="./js/orchestra-9b200011.js"></script>
+  <link rel="modulepreload" crossorigin href="./js/index-c987494a.js">
+  <link rel="modulepreload" crossorigin href="./js/index-27021a09.js">
+  <link rel="modulepreload" crossorigin href="./js/index-d8f93bbd.js">
+  <link rel="modulepreload" crossorigin href="./js/index-666ce298.js">
+  <link rel="stylesheet" href="./css/index-33f3c513.css">
   <link rel="stylesheet" href="./css/index-85f95688.css">
   <link rel="stylesheet" href="./css/index-d42b0794.css">
   <link rel="stylesheet" href="./css/orchestra-8bc1a9c0.css">
@@ -70,8 +70,8 @@
   </script>
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-08e53fef.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/orchestra-legacy-5f41c20f.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b3b6467d.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/orchestra-legacy-4ed40420.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 6 - 6
dist/report-share.html

@@ -2,7 +2,7 @@
 <html lang="en">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-fbd9978d.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-1a2e4f1c.js"></script>
 
   <meta charset="UTF-8" />
   <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
@@ -25,10 +25,10 @@
       transition: opacity .3s;
     }
   </style>
-  <script type="module" crossorigin src="./js/report-share-456da976.js"></script>
-  <link rel="modulepreload" crossorigin href="./js/index-726208cc.js">
+  <script type="module" crossorigin src="./js/report-share-ef089666.js"></script>
+  <link rel="modulepreload" crossorigin href="./js/index-c987494a.js">
   <link rel="modulepreload" crossorigin href="./js/plyr.min-c8c2777b.js">
-  <link rel="stylesheet" href="./css/index-3989851b.css">
+  <link rel="stylesheet" href="./css/index-33f3c513.css">
   <link rel="stylesheet" href="./css/plyr-ad8ef5ae.css">
   <link rel="stylesheet" href="./css/report-share-0f4c3151.css">
   <script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
@@ -51,8 +51,8 @@
   </script>
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-08e53fef.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/report-share-legacy-8df350f4.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b3b6467d.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/report-share-legacy-1420c584.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

BIN
dist/wav/tick-7706b760.wav


BIN
dist/wav/tock-32d5f74b.wav


BIN
src/assets/tick.mp3


BIN
src/assets/tick.wav


BIN
src/assets/tock.mp3


BIN
src/assets/tock.wav


+ 7 - 3
src/helpers/metronome.ts

@@ -9,8 +9,8 @@ import { browser } from "/src/utils/index";
 import state from "/src/state";
 import { Howl } from "howler";
 import tockAndTick from "/src/constant/tockAndTick.json";
-import tickWav from "/src/assets/tick.wav";
-import tockWav from "/src/assets/tock.wav";
+import tickWav from "/src/assets/tick.mp3";
+import tockWav from "/src/assets/tock.mp3";
 
 type IOptions = {
 	speed: number;
@@ -119,7 +119,7 @@ class Metronome {
 		// 	this.source2 = this.loadAudio2();
 		// }
 		// metronomeData.initPlayerState = true;
-
+		if(metronomeData.initPlayerState) return
 		Promise.all([this.createAudio(tickWav), this.createAudio(tockWav)]).then(
 			([tick, tock]) => {
 				if (tick) {
@@ -179,6 +179,10 @@ class Metronome {
 	};
 	// 播放
 	playAudio = () => {
+		/* 如果是 评测模式且不为MIDI并且节拍器资源加载成功的时候  不运行节拍器播放频*/
+		if (state.audioBetaDone && state.modeType === "practise" && state.playMode !== "MIDI") {
+			return
+		}
 		if (!metronomeData.initPlayerState || state.playState === 'paused') return;
 		const beatVolume = state.setting.beatVolume / 100
 		// this.source = metronomeData.activeMetro?.index === 0 ? this.source1 : this.source2;

+ 14 - 2
src/page-instrument/header-top/index.tsx

@@ -54,7 +54,7 @@ export const headTopData = reactive({
       // 如果延迟检测资源还在加载中,给出提示
       if (!evaluatingData.jsonLoadDone) {
         evaluatingData.jsonLoading = true;
-        showToast("资源加载中,请稍后");
+        state.audioDone && showToast("资源加载中,请稍后");  //音频资源加载完之后才提示
         return;
       }
 
@@ -133,6 +133,17 @@ export default defineComponent({
         display: true,
       };
     });
+    /** 节拍器按钮 */
+    const metronomeBtn = computed(() => {
+      // 选择模式  不显示
+      if (headTopData.modeType !== "show") return { display: false, disabled: true };
+      // 音频播放中 禁用
+      if (state.playState === "play") return { display: true, disabled: true };
+      return {
+        disabled: false,
+        display: true,
+      };
+    });
 
     /** 指法按钮 */
     const fingeringBtn = computed(() => {
@@ -481,7 +492,8 @@ export default defineComponent({
             </div>
             {state.modeType !== "evaluating" && (
               <div
-                class={[styles.btn]}
+                style={{ display: metronomeBtn.value.display ? "" : "none" }}
+                class={[styles.btn, metronomeBtn.value.disabled && styles.disabled]}
                 onClick={async () => {
                   metronomeData.disable = !metronomeData.disable;
                   metronomeData.metro?.initPlayer();

+ 3 - 2
src/page-instrument/header-top/settting/index.tsx

@@ -142,7 +142,8 @@ export default defineComponent({
 									extra: () => <Switch v-model={state.setting.eyeProtection}></Switch>,
 								}}
 							</Cell>
-							<Cell
+							{/* 节拍器 音量注释掉了  这里的代码也一并注释了 state.setting.beatVolume = state.setting.beatVolume || 50 */}
+							{/* <Cell
 								title="节拍器音量"
 								class={styles.sliderWrap}
 								center
@@ -161,7 +162,7 @@ export default defineComponent({
 										</Slider>
 									),
 								}}
-							</Cell>							
+							</Cell>							 */}
 							<div class={styles.btnsbar}>
 								{/* <div class={styles.btn} onClick={downPng}>
 									<img src={iconDown} />

+ 3 - 2
src/page-instrument/view-detail/index.tsx

@@ -32,7 +32,7 @@ import { setCustomGradual, setCustomNoteRealValue } from "/src/helpers/customMus
 import { usePageVisibility } from "@vant/use";
 import { initMidi } from "/src/helpers/midiPlay"
 import TheAudio from "/src/components/the-audio"
-import tickWav from "/src/assets/tick.wav";
+import tickWav from "/src/assets/tick.mp3";
 import Title from "../header-top/title";
 import ModeView from "./modeView"
 
@@ -111,7 +111,8 @@ export default defineComponent({
       const settting = store.get("musicscoresetting");
       if (settting) {
         state.setting = settting;
-        state.setting.beatVolume = state.setting.beatVolume || 50
+        //state.setting.beatVolume = state.setting.beatVolume || 50
+        state.setting.beatVolume = 50
         if (state.setting.camera) {
           const res = await api_openCamera();
           // 没有授权

+ 17 - 1
src/state.ts

@@ -1,5 +1,5 @@
 import { closeToast, showToast } from "vant";
-import { nextTick, reactive } from "vue";
+import { nextTick, reactive, watch } from "vue";
 import { OpenSheetMusicDisplay } from "../osmd-extended/src";
 import { metronomeData } from "./helpers/metronome";
 import { GradualNote, GradualTimes, GradualVersion } from "./type";
@@ -14,6 +14,7 @@ import { verifyCanRepeat, getDuration } from "./helpers/formateMusic";
 import { getMusicSheetDetail } from "./utils/baseApi"
 import { getQuery } from "/src/utils/queryString";
 import { followData } from "/src/view/follow-practice/index"
+import { changeSongSourceByBate } from "/src/view/audio-list"
 
 const query: any = getQuery();
 
@@ -450,6 +451,8 @@ const state = reactive({
   midiSectionStart: 0,
   /** 音频文件是否加载完成 */
   audioDone: false,
+  /** 节拍文件是否加载成功 */
+  audioBetaDone: false,
   /** 谱面svgdom节点 */
   osmdSvgDom: null as any,
   /** 滚动容器dom */
@@ -662,6 +665,14 @@ export const skipNotePlay = async (itemIndex: number, isStart = false) => {
   }
 };
 
+/* 还原音频源 */
+watch(()=>state.playState,()=>{
+  // 播放之前  当为评测模式和不为MIDI时候按  是否禁用节拍器  切换音源
+  if (state.audioBetaDone && state.playState==='paused' && state.modeType === "practise" && state.playMode !== "MIDI") {
+    console.log("还原音源")
+    changeSongSourceByBate(true)
+  }
+})
 /**
  * 切换曲谱播放状态
  * @param playState 可选: 默认 undefined, 需要切换的状态 play:播放, paused: 暂停
@@ -672,6 +683,11 @@ export const togglePlay = async (playState?: "play" | "paused", sourceType?: str
     if (sourceType !== 'courseware') showToast('音频资源加载中,请稍后')
     return
   }
+  // 播放之前  当为评测模式和不为MIDI时候按  是否禁用节拍器  切换音源
+  if (state.audioBetaDone && (playState ? playState : state.playState === "paused" ? "play" : "paused") ==='play' && state.modeType === "practise" && state.playMode !== "MIDI") {
+    console.log("设置音源")
+    changeSongSourceByBate(metronomeData.disable)
+  }
   // midi播放
   if (state.isAppPlay) {
     if (playState === "paused") {

+ 196 - 0
src/utils/crunker.ts

@@ -0,0 +1,196 @@
+interface CrunkerConstructorOptions {
+   sampleRate: number
+   concurrentNetworkRequests: number
+}
+
+type CrunkerInputTypes = string | File | Blob
+
+export default class Crunker {
+   private readonly _sampleRate: number
+   private readonly _concurrentNetworkRequests: number
+   private readonly _context: AudioContext
+
+   constructor({ sampleRate, concurrentNetworkRequests = 200 }: Partial<CrunkerConstructorOptions> = {}) {
+      this._context = this._createContext(sampleRate)
+      sampleRate ||= this._context.sampleRate
+      this._sampleRate = sampleRate
+      this._concurrentNetworkRequests = concurrentNetworkRequests
+   }
+   private _createContext(sampleRate = 44_100): AudioContext {
+      window.AudioContext = window.AudioContext || (window as any).webkitAudioContext || (window as any).mozAudioContext
+      return new AudioContext({ sampleRate })
+   }
+   /**
+    *转换url等类型为buffer
+    */
+   async fetchAudio(...filepaths: CrunkerInputTypes[]): Promise<AudioBuffer[]> {
+      const buffers: AudioBuffer[] = []
+      const groups = Math.ceil(filepaths.length / this._concurrentNetworkRequests)
+      for (let i = 0; i < groups; i++) {
+         const group = filepaths.slice(i * this._concurrentNetworkRequests, (i + 1) * this._concurrentNetworkRequests)
+         buffers.push(...(await this._fetchAudio(...group)))
+      }
+      return buffers
+   }
+   private async _fetchAudio(...filepaths: CrunkerInputTypes[]): Promise<AudioBuffer[]> {
+      return await Promise.all(
+         filepaths.map(async filepath => {
+            let buffer: ArrayBuffer
+            if (filepath instanceof File || filepath instanceof Blob) {
+               buffer = await filepath.arrayBuffer()
+            } else {
+               buffer = await fetch(filepath).then(response => {
+                  if (response.headers.has("Content-Type") && !response.headers.get("Content-Type")!.includes("audio/")) {
+                     console.warn(
+                        `Crunker: Attempted to fetch an audio file, but its MIME type is \`${
+                           response.headers.get("Content-Type")!.split(";")[0]
+                        }\`. We'll try and continue anyway. (file: "${filepath}")`
+                     )
+                  }
+                  return response.arrayBuffer()
+               })
+            }
+            /* 这里有个坑 safa浏览器老一点的版本不支持decodeAudioData返回promise 所以用这种老式写法 */
+            return await new Promise((res, rej) => {
+               this._context.decodeAudioData(
+                  buffer,
+                  buffer => {
+                     res(buffer)
+                  },
+                  err => {
+                     rej(err)
+                  }
+               )
+            })
+         })
+      )
+   }
+   /**
+    * 根据时间合并音频
+    */
+   mergeAudioBuffers(buffers: AudioBuffer[], times: number[]): AudioBuffer {
+      if (buffers.length !== times.length) {
+         throw new Error("buffer数量和times数量必须一致")
+      }
+      const output = this._context.createBuffer(this._maxNumberOfChannels(buffers), this._sampleRate * this._maxDuration(buffers), this._sampleRate)
+      buffers.forEach((buffer, index) => {
+         for (let channelNumber = 0; channelNumber < buffer.numberOfChannels; channelNumber++) {
+            const outputData = output.getChannelData(channelNumber)
+            const bufferData = buffer.getChannelData(channelNumber)
+            const offsetNum = Math.round(times[index] * this._sampleRate) //时间偏差
+            for (let i = buffer.getChannelData(channelNumber).length - 1; i >= 0; i--) {
+               outputData[i + offsetNum] += bufferData[i]
+               // 当合并大于1或者小于-1的时候可能会爆音  所以这里取最大值和最小值
+               if (outputData[i + offsetNum] > 1) {
+                  outputData[i + offsetNum] = 1
+               }
+               if (outputData[i + offsetNum] < -1) {
+                  outputData[i + offsetNum] = -1
+               }
+            }
+            output.getChannelData(channelNumber).set(outputData)
+         }
+      })
+
+      return output
+   }
+   /**
+    * 根据buffer导出audio标签
+    */
+   exportAudioElement(buffer: AudioBuffer, type = "audio/mp3"): HTMLAudioElement {
+      const recorded = this._interleave(buffer)
+      const dataview = this._writeHeaders(recorded, buffer.numberOfChannels, buffer.sampleRate)
+      const audioBlob = new Blob([dataview], { type })
+      return this._renderAudioElement(audioBlob)
+   }
+   /**
+    * 计算音频前面的空白
+    */
+   calculateSilenceDuration(buffer: AudioBuffer) {
+      const threshold = 0.01 // 静音阈值,低于此值的部分认为是静音
+      const sampleRate = buffer.sampleRate
+      const channelData = buffer.getChannelData(0) // 只处理单声道数据
+      let silenceDuration = 0
+      for (let i = 0; i < channelData.length; i++) {
+         if (Math.abs(channelData[i]) > threshold) {
+            break
+         }
+         silenceDuration++
+      }
+      // 将样本数转换为秒
+      silenceDuration = silenceDuration / sampleRate
+      return silenceDuration
+   }
+   private _maxNumberOfChannels(buffers: AudioBuffer[]): number {
+      return Math.max(...buffers.map(buffer => buffer.numberOfChannels))
+   }
+   private _maxDuration(buffers: AudioBuffer[]): number {
+      return Math.max(...buffers.map(buffer => buffer.duration))
+   }
+   private _interleave(input: AudioBuffer): Float32Array {
+      if (input.numberOfChannels === 1) {
+         return input.getChannelData(0)
+      }
+      const channels = []
+      for (let i = 0; i < input.numberOfChannels; i++) {
+         channels.push(input.getChannelData(i))
+      }
+      const length = channels.reduce((prev, channelData) => prev + channelData.length, 0)
+      const result = new Float32Array(length)
+      let index = 0
+      let inputIndex = 0
+      while (index < length) {
+         channels.forEach(channelData => {
+            result[index++] = channelData[inputIndex]
+         })
+         inputIndex++
+      }
+      return result
+   }
+   private _renderAudioElement(blob: Blob): HTMLAudioElement {
+      const audio = document.createElement("audio")
+      audio.src = this._renderURL(blob)
+      audio.load()
+      return audio
+   }
+   private _renderURL(blob: Blob): string {
+      return (window.URL || window.webkitURL).createObjectURL(blob)
+   }
+   private _writeHeaders(buffer: Float32Array, numOfChannels: number, sampleRate: number): DataView {
+      const bitDepth = 16
+      const bytesPerSample = bitDepth / 8
+      const sampleSize = numOfChannels * bytesPerSample
+      const fileHeaderSize = 8
+      const chunkHeaderSize = 36
+      const chunkDataSize = buffer.length * bytesPerSample
+      const chunkTotalSize = chunkHeaderSize + chunkDataSize
+      const arrayBuffer = new ArrayBuffer(fileHeaderSize + chunkTotalSize)
+      const view = new DataView(arrayBuffer)
+      this._writeString(view, 0, "RIFF")
+      view.setUint32(4, chunkTotalSize, true)
+      this._writeString(view, 8, "WAVE")
+      this._writeString(view, 12, "fmt ")
+      view.setUint32(16, 16, true)
+      view.setUint16(20, 1, true)
+      view.setUint16(22, numOfChannels, true)
+      view.setUint32(24, sampleRate, true)
+      view.setUint32(28, sampleRate * sampleSize, true)
+      view.setUint16(32, sampleSize, true)
+      view.setUint16(34, bitDepth, true)
+      this._writeString(view, 36, "data")
+      view.setUint32(40, chunkDataSize, true)
+      return this._floatTo16BitPCM(view, buffer, fileHeaderSize + chunkHeaderSize)
+   }
+   private _floatTo16BitPCM(dataview: DataView, buffer: Float32Array, offset: number): DataView {
+      for (let i = 0; i < buffer.length; i++, offset += 2) {
+         const tmp = Math.max(-1, Math.min(1, buffer[i]))
+         dataview.setInt16(offset, tmp < 0 ? tmp * 0x8000 : tmp * 0x7fff, true)
+      }
+      return dataview
+   }
+   private _writeString(dataview: DataView, offset: number, header: string): void {
+      for (let i = 0; i < header.length; i++) {
+         dataview.setUint8(offset + i, header.charCodeAt(i))
+      }
+   }
+}

BIN
src/view/audio-list/img/icon_loading_head.png


BIN
src/view/audio-list/img/icon_loading_img.png


+ 61 - 0
src/view/audio-list/index.module.less

@@ -4,4 +4,65 @@
     bottom: 0;
     width: 100%;
     z-index: -1000000;
+}
+
+.loading {
+    position: fixed;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 10000;
+    background: rgba(0, 0, 0, .6);
+}
+
+.loadingWrap {
+    position: relative;
+    width: 295px;
+    padding: 21px 17px;
+    background: rgba(135, 135, 135, .72);
+    border-radius: 24px;
+
+    .loadingIcon {
+        position: absolute;
+        left: 50%;
+        top: -35px;
+        transform: translateX(-50%);
+        width: 216px;
+    }
+
+    .loadingTip {
+        position: absolute;
+        left: 50%;
+        transform: translateX(-50%);
+        bottom: -35px;
+        color: #fff;
+        font-size: 13px;
+        font-weight: 400px;
+    }
+
+    :global {
+        .van-progress {
+            height: 7px;
+        }
+
+        .van-progress__portion {
+            background: linear-gradient(180deg, #3CD6F9 0%, #1CACF1 100%);
+            border: 1px solid rgba(255, 255, 255, .5);
+        }
+
+        .van-progress__pivot {
+            top: 0;
+            color: transparent;
+            background-color: transparent;
+            width: 35px;
+            height: 37px;
+            background-image: url('./img/icon_loading_head.png');
+            background-repeat: no-repeat;
+            background-size: 100% 100%;
+        }
+    }
 }

+ 135 - 32
src/view/audio-list/index.tsx

@@ -12,10 +12,22 @@ import state, { IPlayState, onEnded, onPlay } from "/src/state";
 import { api_playProgress, api_cloudTimeUpdae, api_cloudplayed, api_remove_cloudplayed, api_remove_cloudTimeUpdae } from "/src/helpers/communication";
 import { evaluatingData } from "/src/view/evaluating";
 import { cloudToggleState } from "/src/helpers/midiPlay"
+import { metronomeData } from "../../helpers/metronome";
+import Crunker from "../../utils/crunker"
+const crunker = new Crunker()
+import tickWav from "/src/assets/tick.mp3";
+import tockWav from "/src/assets/tock.mp3";
+import Loading from "./loading"
 
 export const audioData = reactive({
 	songEle: null as unknown as HTMLAudioElement,
 	backgroundEle: null as unknown as HTMLAudioElement,
+	songCollection: {  // 音乐源合集   beatSongEle和bateBackgroundEle是带节拍的音乐源   评测模式的时候用
+		songEle: null as unknown as HTMLAudioElement,
+		backgroundEle: null as unknown as HTMLAudioElement,
+		beatSongEle: null as unknown as HTMLAudioElement,
+		bateBackgroundEle: null as unknown as HTMLAudioElement,
+	},
 	midiRender: false,
 	progress: 0, // midi播放进度(单位:秒)
 	duration: 0 // 音频总时长(单位:秒)
@@ -112,6 +124,37 @@ export const detectTheNumberOfSoundSources = () => {
 	return total;
 };
 
+/** 切换节拍器音源 */
+export const changeSongSourceByBate = (isDisBate:boolean) => {
+	// isDisBate 为true 切换到不带节拍的,为false 切换到带节拍的
+	if(audioData.songCollection.songEle && audioData.songCollection.beatSongEle){
+		const songEleCurrentTime = audioData.songEle.currentTime
+		console.log("当前音乐时间:",songEleCurrentTime)
+		if(isDisBate){
+			audioData.songEle = audioData.songCollection.songEle
+			audioData.songEle.currentTime = songEleCurrentTime
+			if(audioData.songCollection.backgroundEle){
+				audioData.backgroundEle = audioData.songCollection.backgroundEle
+				audioData.backgroundEle.currentTime = songEleCurrentTime
+			}
+		}else{
+			audioData.songEle = audioData.songCollection.beatSongEle
+			audioData.songEle.currentTime = songEleCurrentTime
+			if(audioData.songCollection.bateBackgroundEle){
+				audioData.backgroundEle = audioData.songCollection.bateBackgroundEle
+				audioData.backgroundEle.currentTime = songEleCurrentTime
+			}
+		}
+	}
+	// 设置静音与取消静音
+	if (state.playSource === "music") {
+		audioData.songEle && (audioData.songEle.muted = false);
+		audioData.backgroundEle && (audioData.backgroundEle.muted = true);
+	} else {
+		audioData.songEle && (audioData.songEle.muted = true);
+		audioData.backgroundEle && (audioData.backgroundEle.muted = false);
+	}
+}
 export default defineComponent({
 	name: "audio-list",
 	setup() {
@@ -202,32 +245,89 @@ export default defineComponent({
 				onEnded();
 			}
 		}
-
-		onMounted(() => {
+		// 合成节拍器音源
+		function loadMergeAudioBetas() {
+			console.time("音频加载时间")
+			const audioList = [state.music+'?v='+Date.now()]
+			if(state.accompany){   // 可能存在没有伴奏的音源
+				audioList.push(state.accompany+'?v='+Date.now()) 
+			}
+			return crunker.fetchAudio(tickWav, tockWav, ...audioList).then(([tickWavBuff,tockWavBuff,musicBuff,accompanyBuff])=>{
+				console.timeEnd("音频加载时间")
+				// 计算音频空白时间
+				const silenceDuration = crunker.calculateSilenceDuration(musicBuff)
+				const silenceBgDuration = accompanyBuff && crunker.calculateSilenceDuration(accompanyBuff) 
+				console.log(`音频空白时间:${silenceDuration},${silenceBgDuration}`)
+				const beats:AudioBuffer[] = []
+				const beatsTime:number[] = []
+				const beatsBgTime:number[] = []
+				metronomeData.metroMeasure.map(Measures=>{
+					Measures.map((item:any)=>{
+						beats.push(item.index===0?tickWavBuff:tockWavBuff)
+						beatsTime.push(item.time + silenceDuration) // xml 计算的时候 加上空白的时间
+						accompanyBuff && beatsBgTime.push(item.time + silenceBgDuration) // xml 计算的时候 加上空白的时间
+					})
+				})
+				//合并
+				console.time("音频合并时间")
+				const musicBuffMeg = crunker.mergeAudioBuffers([musicBuff,...beats],[0,...beatsTime])
+				const accompanyBuffMeg = accompanyBuff && crunker.mergeAudioBuffers([accompanyBuff,...beats],[0,...beatsBgTime])
+				console.timeEnd("音频合并时间")
+				return [musicBuffMeg,accompanyBuffMeg]
+			}).then(([musicBuffMeg,accompanyBuffMeg])=>{
+				console.time("音频audioDom生成时间")
+				const musicAudio = crunker.exportAudioElement(musicBuffMeg)
+				const accompanyAudio = accompanyBuffMeg && crunker.exportAudioElement(accompanyBuffMeg)
+				console.timeEnd("音频audioDom生成时间")
+				return [musicAudio,accompanyAudio]
+			})
+		}
+		// 加载普通音源
+		function loadAudio(){
+			return Promise.all([createAudio(state.music), createAudio(state.accompany)])
+		}
+		onMounted(async () => {
 			if (state.playMode !== "MIDI") {
-				Promise.all([createAudio(state.music), createAudio(state.accompany)]).then(
-					([music, accompany]) => {
-						state.audioDone = true;
-						// console.log(music, accompany);
-						if (music) {
-							audioData.songEle = music;
-						}
-						if (accompany) {
-							audioData.backgroundEle = accompany;
-						}
-						if (audioData.songEle) {
-							audioData.songEle.addEventListener("play", onPlay);
-							audioData.songEle.addEventListener("ended", onEnded);
-							accompany && (accompany.muted = true);
-						} else if (audioData.backgroundEle) {
-							audioData.backgroundEle.addEventListener("play", onPlay);
-							audioData.backgroundEle.addEventListener("ended", onEnded);
-						}
+				console.time("加载资源耗时")
+				// 不带节拍的音源
+				const [music, accompany] = await loadAudio()
+				try {
+					// 带节拍的音源
+					const [musicAudio,accompanyAudio] = await loadMergeAudioBetas()
+					console.log("音频合成成功66666666")
+					state.audioBetaDone = true;
+					if (musicAudio) {
+						musicAudio.addEventListener("play", onPlay);
+						musicAudio.addEventListener("ended", onEnded);
+						accompanyAudio && (accompanyAudio.muted = true);
+					} else if (accompanyAudio) {
+						accompanyAudio.addEventListener("play", onPlay);
+						accompanyAudio.addEventListener("ended", onEnded);
 					}
-				);
-
+					Object.assign(audioData.songCollection,{
+						songEle:music,
+						backgroundEle:accompany,
+						beatSongEle:musicAudio,
+						bateBackgroundEle:accompanyAudio
+					})
+				} catch (err) {
+					console.log("音频合成失败7777777:",err)
+				}
+				state.audioDone = true;
+				audioData.backgroundEle = accompany!;
+				audioData.songEle = music!;
+				if (music) {
+					music.addEventListener("play", onPlay);
+					music.addEventListener("ended", onEnded);
+					accompany && (accompany.muted = true);
+				} else if (accompany) {
+					accompany.addEventListener("play", onPlay);
+					accompany.addEventListener("ended", onEnded);
+				}
+				console.timeEnd("加载资源耗时")
 				api_playProgress(progress);
 			} else {
+				state.audioDone = true;
 				const songEndTime = state.times[state.times.length - 1 || 0]?.endtime || 0
 				audioData.duration = songEndTime
 				// 监听midi播放进度
@@ -243,16 +343,19 @@ export default defineComponent({
 
 		// console.log(state.playMode, state.midiUrl);
 		return () => (
-			<div class={styles.audioList}>
-				{state.playMode === "MIDI" && state.speed != 0 && (
-					<iframe
-						style={{ display: "none" }}
-						ref={midiRef}
-						src={`/midi/index.html`}
-						onLoad={handleLoad}
-					/>
-				)}
-			</div>
+			<>
+				<Loading/>
+				<div class={styles.audioList}>
+					{state.playMode === "MIDI" && state.speed != 0 && (
+						<iframe
+							style={{ display: "none" }}
+							ref={midiRef}
+							src={`/midi/index.html`}
+							onLoad={handleLoad}
+						/>
+					)}
+				</div>
+			</>
 		);
 	},
 });

+ 39 - 0
src/view/audio-list/loading.tsx

@@ -0,0 +1,39 @@
+import { defineComponent, ref } from "vue"
+import icon_loading_img from "./img/icon_loading_img.png"
+import { Progress } from "vant"
+import styles from "./index.module.less"
+import state from "/src/state"
+
+export default defineComponent({
+   name: "loading",
+   setup() {
+      function fakeLoadingProgress(duration = 2000, callback: (num: number) => void) {
+         let startTime = Date.now()
+         let progress = 0
+         const timer = setInterval(() => {
+            let timePassed = Date.now() - startTime
+            if (timePassed >= duration) {
+               clearInterval(timer)
+               callback(96) // 进度完成
+               return
+            }
+            progress = Math.min(100, (timePassed / duration) * 100)
+            callback(progress)
+         }, 300)
+      }
+      const loadingProress = ref(0)
+      fakeLoadingProgress(2000, num => {
+         loadingProress.value = num
+      })
+      return () =>
+         !state.audioDone && (
+            <div class={styles.loading}>
+               <div class={styles.loadingWrap}>
+                  <img class={styles.loadingIcon} src={icon_loading_img} />
+                  <Progress percentage={loadingProress.value} />
+                  <div class={styles.loadingTip}>音频资源加载中,请稍后</div>
+               </div>
+            </div>
+         )
+   }
+})

+ 11 - 11
src/view/tick/index.tsx

@@ -5,8 +5,8 @@ import { Popup } from "vant";
 import styles from "./index.module.less";
 import state from "/src/state";
 import { browser } from "/src/utils/index";
-import tickWav from "/src/assets/tick.wav";
-import tockWav from "/src/assets/tock.wav";
+import tickWav from "/src/assets/tick.mp3";
+import tockWav from "/src/assets/tock.mp3";
 
 const browserInfo = browser();
 export const tickData = reactive({
@@ -53,7 +53,7 @@ const audioData = reactive({
 
 const createAudio = (src: string): Promise<HTMLAudioElement | null> => {
 	return new Promise((resolve) => {
-		const a = new Audio(src + '?v=' + Date.now());
+		const a = new Audio(src);
 		a.load();
 		a.onloadedmetadata = () => {
 			resolve(a);
@@ -79,15 +79,15 @@ export const handleStartTick = async () => {
 	tickData.show = true;
 	tickData.tickEnd = false;
 	if (tickData.state !== "ok") {
-		tickData.source1 = new Howl({
-			src: tockAndTick.tick,
-			// 如果是ios手机,需要强制使用audio,不然部分系统版本第一次播放没有声音
-			html5: browserInfo.ios,
-		});
+		// tickData.source1 = new Howl({
+		// 	src: tockAndTick.tick,
+		// 	// 如果是ios手机,需要强制使用audio,不然部分系统版本第一次播放没有声音
+		// 	html5: browserInfo.ios,
+		// });
 
-		tickData.source2 = new Howl({
-			src: tockAndTick.tock,
-		});
+		// tickData.source2 = new Howl({
+		// 	src: tockAndTick.tock,
+		// });
 		tickData.state = "ok";
 	}
 	tickData.index = 0;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
stats.html


+ 1 - 1
vite.config.ts

@@ -78,7 +78,7 @@ export default defineConfig({
         // target: "https://kt.colexiu.com",
         // target: "https://test.resource.colexiu.com", // 内容平台开发环境,内容平台开发,需在url链接上加上isCbs=true
         // target: "https://dev.resource.colexiu.com",
-         target: "https://test.kt.colexiu.com",
+        target: "https://test.kt.colexiu.com",
         //target: "https://mec.colexiu.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/instrument/, ""),

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است