Spaces:
Runtime error
Runtime error
xribene
commited on
Commit
·
df4b493
1
Parent(s):
7687352
first
Browse files- .editorconfig +19 -0
- .gitignore +24 -0
- app.py +66 -0
- frontend/README.md +7 -0
- frontend/eslint.config.js +31 -0
- frontend/index.html +18 -0
- frontend/package-lock.json +0 -0
- frontend/package.json +56 -0
- frontend/pnpm-lock.yaml +0 -0
- frontend/public/_headers +1 -0
- frontend/public/cedar_guitar_1663.png +0 -0
- frontend/public/cedar_guitar_400.png +0 -0
- frontend/public/cedar_guitar_800.png +0 -0
- frontend/public/example.xml +0 -0
- frontend/public/g14671.png +0 -0
- frontend/public/g9541.png +0 -0
- frontend/public/guitar-diff-example.musicxml +507 -0
- frontend/public/guitar-diff-example.vextab.txt +6 -0
- frontend/public/guitarDiffLogo2.svg +0 -0
- frontend/public/guitarDiffLogo3.svg +0 -0
- frontend/public/guitar_faded_noReport.png +0 -0
- frontend/public/guitar_rotated.svg +0 -0
- frontend/public/guitar_rotated_report.svg +0 -0
- frontend/public/guitar_straight.svg +0 -0
- frontend/public/inkscape_canvas.svg +0 -0
- frontend/public/test.svg +0 -0
- frontend/public/vite.svg +1 -0
- frontend/src/App.vue +89 -0
- frontend/src/assets/vue.svg +1 -0
- frontend/src/components/CounterButton.vue +20 -0
- frontend/src/components/HelloWorld.vue +42 -0
- frontend/src/components/MusicXmlWidget.vue +320 -0
- frontend/src/components/TweakComponent.vue +26 -0
- frontend/src/components/TweakComponent2.vue +107 -0
- frontend/src/components/VextabWidget.vue +225 -0
- frontend/src/main.js +51 -0
- frontend/src/plugins/router.js +21 -0
- frontend/src/style.css +157 -0
- frontend/src/views/Analyzer.vue +197 -0
- frontend/src/views/Home.vue +33 -0
- frontend/uno.config.js +46 -0
- frontend/vite.config.js +21 -0
- pyproject.toml +70 -0
.editorconfig
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# top-most EditorConfig file
|
2 |
+
root = true
|
3 |
+
|
4 |
+
[*]
|
5 |
+
indent_style = space
|
6 |
+
indent_size = 2
|
7 |
+
end_of_line = crlf
|
8 |
+
charset = utf-8
|
9 |
+
trim_trailing_whitespace = true
|
10 |
+
insert_final_newline = true
|
11 |
+
|
12 |
+
[*.py]
|
13 |
+
indent_size = 4
|
14 |
+
|
15 |
+
[*.{js,vue}]
|
16 |
+
indent_size = 2
|
17 |
+
|
18 |
+
[*.vue]
|
19 |
+
indent_size = 2
|
.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Logs
|
2 |
+
logs
|
3 |
+
*.log
|
4 |
+
npm-debug.log*
|
5 |
+
yarn-debug.log*
|
6 |
+
yarn-error.log*
|
7 |
+
pnpm-debug.log*
|
8 |
+
lerna-debug.log*
|
9 |
+
|
10 |
+
node_modules
|
11 |
+
dist
|
12 |
+
dist-ssr
|
13 |
+
*.local
|
14 |
+
|
15 |
+
# Editor directories and files
|
16 |
+
.vscode/*
|
17 |
+
!.vscode/extensions.json
|
18 |
+
.idea
|
19 |
+
.DS_Store
|
20 |
+
*.suo
|
21 |
+
*.ntvs*
|
22 |
+
*.njsproj
|
23 |
+
*.sln
|
24 |
+
*.sw?
|
app.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import gradio as gr
|
2 |
+
|
3 |
+
|
4 |
+
# def process(name):
|
5 |
+
# return "Hello re malakako" + name + "!"
|
6 |
+
|
7 |
+
|
8 |
+
# with gr.Blocks() as demo:
|
9 |
+
# name = gr.Textbox(label="Score (vextab or musicxml)")
|
10 |
+
# output = gr.Textbox(label="Difficulty Analysis Report")
|
11 |
+
# greet_btn = gr.Button("Process")
|
12 |
+
# greet_btn.click(fn=process, inputs=name, outputs=output, api_name="process")
|
13 |
+
|
14 |
+
# demo.launch()
|
15 |
+
|
16 |
+
|
17 |
+
import time
|
18 |
+
import gradio as gr
|
19 |
+
|
20 |
+
|
21 |
+
def fake_diffusion(steps):
|
22 |
+
for i in range(steps):
|
23 |
+
print(f"Current step: {i}")
|
24 |
+
time.sleep(1)
|
25 |
+
yield str(i)
|
26 |
+
|
27 |
+
|
28 |
+
def long_prediction(*args, **kwargs):
|
29 |
+
time.sleep(10)
|
30 |
+
return 42
|
31 |
+
|
32 |
+
|
33 |
+
with gr.Blocks() as demo:
|
34 |
+
with gr.Row():
|
35 |
+
with gr.Column():
|
36 |
+
n = gr.Slider(1, 10, value=9, step=1, label="Number Steps")
|
37 |
+
run = gr.Button(value="Start Iterating")
|
38 |
+
output = gr.Textbox(label="Iterative Output")
|
39 |
+
stop = gr.Button(value="Stop Iterating")
|
40 |
+
with gr.Column():
|
41 |
+
textbox = gr.Textbox(label="Prompt")
|
42 |
+
prediction = gr.Number(label="Expensive Calculation")
|
43 |
+
run_pred = gr.Button(value="Run Expensive Calculation")
|
44 |
+
with gr.Column():
|
45 |
+
cancel_on_change = gr.Textbox(label="Cancel Iteration and Expensive Calculation on Change")
|
46 |
+
cancel_on_submit = gr.Textbox(label="Cancel Iteration and Expensive Calculation on Submit")
|
47 |
+
echo = gr.Textbox(label="Echo")
|
48 |
+
with gr.Row():
|
49 |
+
with gr.Column():
|
50 |
+
image = gr.Image(sources=["webcam"], label="Cancel on clear", interactive=True)
|
51 |
+
with gr.Column():
|
52 |
+
video = gr.Video(sources=["webcam"], label="Cancel on start recording", interactive=True)
|
53 |
+
|
54 |
+
click_event = run.click(fake_diffusion, n, output)
|
55 |
+
stop.click(fn=None, inputs=None, outputs=None, cancels=[click_event])
|
56 |
+
pred_event = run_pred.click(fn=long_prediction, inputs=[textbox], outputs=prediction)
|
57 |
+
|
58 |
+
cancel_on_change.change(None, None, None, cancels=[click_event, pred_event])
|
59 |
+
cancel_on_submit.submit(lambda s: s, cancel_on_submit, echo, cancels=[click_event, pred_event])
|
60 |
+
image.clear(None, None, None, cancels=[click_event, pred_event])
|
61 |
+
video.start_recording(None, None, None, cancels=[click_event, pred_event])
|
62 |
+
|
63 |
+
demo.queue(max_size=20)
|
64 |
+
|
65 |
+
if __name__ == "__main__":
|
66 |
+
demo.launch()
|
frontend/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Vue 3 + Vite
|
2 |
+
|
3 |
+
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
4 |
+
|
5 |
+
## Recommended IDE Setup
|
6 |
+
|
7 |
+
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
frontend/eslint.config.js
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import antfu from '@antfu/eslint-config'
|
2 |
+
|
3 |
+
export default antfu(
|
4 |
+
{
|
5 |
+
// customizations
|
6 |
+
rules: {
|
7 |
+
'no-unused-vars': 'off',
|
8 |
+
'unused-imports/no-unused-vars': 'off',
|
9 |
+
'no-console': 'off',
|
10 |
+
},
|
11 |
+
unocss: true,
|
12 |
+
formatters: {
|
13 |
+
/**
|
14 |
+
* Format CSS, LESS, SCSS files, also the `<style>` blocks in Vue
|
15 |
+
* By default uses Prettier
|
16 |
+
*/
|
17 |
+
// css: true,
|
18 |
+
/**
|
19 |
+
* Format HTML files
|
20 |
+
* By default uses Prettier
|
21 |
+
*/
|
22 |
+
// html: true,
|
23 |
+
/**
|
24 |
+
* Format Markdown files
|
25 |
+
* Supports Prettier and dprint
|
26 |
+
* By default uses Prettier
|
27 |
+
*/
|
28 |
+
// markdown: 'prettier',
|
29 |
+
},
|
30 |
+
},
|
31 |
+
)
|
frontend/index.html
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<!-- <meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin">
|
5 |
+
<meta http-equiv="Cross-Origin-Embedder-Policy" content="require-corp"> -->
|
6 |
+
<meta charset="UTF-8" />
|
7 |
+
<link rel="icon" type="image/svg+xml" href="/cedar_guitar_400.png" />
|
8 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
9 |
+
|
10 |
+
<script src="https://cdn.jsdelivr.net/npm/vexflow@4.2.3/build/cjs/vexflow.min.js"></script>
|
11 |
+
<script src="https://cdn.jsdelivr.net/npm/vextab@2.0.13/releases/vextab-div.js"></script>
|
12 |
+
<title>Guitar Diff</title>
|
13 |
+
</head>
|
14 |
+
<body>
|
15 |
+
<div id="app"></div>
|
16 |
+
<script type="module" src="/src/main.js"></script>
|
17 |
+
</body>
|
18 |
+
</html>
|
frontend/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
frontend/package.json
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "guitar-diff-client",
|
3 |
+
"type": "module",
|
4 |
+
"version": "0.1.0",
|
5 |
+
"private": true,
|
6 |
+
"scripts": {
|
7 |
+
"dev": "vite",
|
8 |
+
"build": "vite build",
|
9 |
+
"preview": "vite preview",
|
10 |
+
"up": "taze major -I",
|
11 |
+
"lint": "eslint .",
|
12 |
+
"lint:fix": "eslint . --fix"
|
13 |
+
},
|
14 |
+
"dependencies": {
|
15 |
+
"@coderline/alphatab": "^1.2.3",
|
16 |
+
"@gradio/client": "^0.9.4",
|
17 |
+
"@pangenerator/tweakpane-textarea-plugin": "github:kitschpatrol/tweakpane-textarea-plugin#tweakpane-v4",
|
18 |
+
"@tweakpane/plugin-essentials": "^0.2.1",
|
19 |
+
"@unocss/preset-icons": "^0.58.2",
|
20 |
+
"i": "^0.3.7",
|
21 |
+
"opensheetmusicdisplay": "^1.8.4",
|
22 |
+
"tweakpane": "^4.0.3",
|
23 |
+
"unocss": "^0.58.2",
|
24 |
+
"v-github-icon": "^3.1.2",
|
25 |
+
"v-tweakpane": "github:vinayakkulkarni/v-tweakpane#main",
|
26 |
+
"vexflow": "4.2.3",
|
27 |
+
"vextab": "3.0.6",
|
28 |
+
"vue": "^3.3.13",
|
29 |
+
"vue-meta": "^3.0.0-alpha.10",
|
30 |
+
"vue-router": "^4.2.5",
|
31 |
+
"vue3-tabs-component": "^1.3.7",
|
32 |
+
"vuetify": "^3.4.9"
|
33 |
+
},
|
34 |
+
"devDependencies": {
|
35 |
+
"@antfu/eslint-config": "^2.6.1",
|
36 |
+
"@iconify/json": "^2.2.162",
|
37 |
+
"@mdi/font": "^7.4.47",
|
38 |
+
"@unocss/eslint-plugin": "^0.58.2",
|
39 |
+
"@vitejs/plugin-vue": "^5.0.0",
|
40 |
+
"eslint": "^8.56.0",
|
41 |
+
"eslint-config-google": "^0.14.0",
|
42 |
+
"eslint-flat-config-viewer": "0.1.3",
|
43 |
+
"eslint-plugin-format": "^0.1.0",
|
44 |
+
"eslint-plugin-vue": "^9.19.2",
|
45 |
+
"lint-staged": "^15.2.0",
|
46 |
+
"simple-git-hooks": "^2.9.0",
|
47 |
+
"taze": "^0.13.1",
|
48 |
+
"vite": "^5.0.10"
|
49 |
+
},
|
50 |
+
"simple-git-hooks": {
|
51 |
+
"pre-commit": "pnpm lint-staged"
|
52 |
+
},
|
53 |
+
"lint-staged": {
|
54 |
+
"*": "eslint --fix"
|
55 |
+
}
|
56 |
+
}
|
frontend/pnpm-lock.yaml
ADDED
The diff for this file is too large to render.
See raw diff
|
|
frontend/public/_headers
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
|
frontend/public/cedar_guitar_1663.png
ADDED
![]() |
frontend/public/cedar_guitar_400.png
ADDED
![]() |
frontend/public/cedar_guitar_800.png
ADDED
![]() |
frontend/public/example.xml
ADDED
The diff for this file is too large to render.
See raw diff
|
|
frontend/public/g14671.png
ADDED
![]() |
frontend/public/g9541.png
ADDED
![]() |
frontend/public/guitar-diff-example.musicxml
ADDED
@@ -0,0 +1,507 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
|
3 |
+
<score-partwise version="3.1">
|
4 |
+
<work>
|
5 |
+
<work-title>Fantasia no.2 </work-title>
|
6 |
+
</work>
|
7 |
+
<identification>
|
8 |
+
<creator type="composer">Michalis Sourvinos</creator>
|
9 |
+
<encoding>
|
10 |
+
<software>MuseScore 3.6.2</software>
|
11 |
+
<encoding-date>2023-11-28</encoding-date>
|
12 |
+
<supports element="accidental" type="yes"/>
|
13 |
+
<supports element="beam" type="yes"/>
|
14 |
+
<supports element="print" attribute="new-page" type="yes" value="yes"/>
|
15 |
+
<supports element="print" attribute="new-system" type="yes" value="yes"/>
|
16 |
+
<supports element="stem" type="yes"/>
|
17 |
+
</encoding>
|
18 |
+
</identification>
|
19 |
+
<defaults>
|
20 |
+
<scaling>
|
21 |
+
<millimeters>6.99912</millimeters>
|
22 |
+
<tenths>40</tenths>
|
23 |
+
</scaling>
|
24 |
+
<page-layout>
|
25 |
+
<page-height>1596.77</page-height>
|
26 |
+
<page-width>1233.87</page-width>
|
27 |
+
<page-margins type="even">
|
28 |
+
<left-margin>85.7251</left-margin>
|
29 |
+
<right-margin>85.7251</right-margin>
|
30 |
+
<top-margin>85.7251</top-margin>
|
31 |
+
<bottom-margin>85.7251</bottom-margin>
|
32 |
+
</page-margins>
|
33 |
+
<page-margins type="odd">
|
34 |
+
<left-margin>85.7251</left-margin>
|
35 |
+
<right-margin>85.7251</right-margin>
|
36 |
+
<top-margin>85.7251</top-margin>
|
37 |
+
<bottom-margin>85.7251</bottom-margin>
|
38 |
+
</page-margins>
|
39 |
+
</page-layout>
|
40 |
+
<word-font font-family="Edwin" font-size="10"/>
|
41 |
+
<lyric-font font-family="Edwin" font-size="10"/>
|
42 |
+
</defaults>
|
43 |
+
<credit page="1">
|
44 |
+
<credit-type>title</credit-type>
|
45 |
+
<credit-words default-x="616.935" default-y="1511.05" justify="center" valign="top" font-size="22">Fantasia no.2 </credit-words>
|
46 |
+
</credit>
|
47 |
+
<credit page="1">
|
48 |
+
<credit-type>subtitle</credit-type>
|
49 |
+
<credit-words default-x="616.935" default-y="1453.9" justify="center" valign="top" font-size="16">in A major</credit-words>
|
50 |
+
</credit>
|
51 |
+
<credit page="1">
|
52 |
+
<credit-type>composer</credit-type>
|
53 |
+
<credit-words default-x="1148.14" default-y="1411.05" justify="right" valign="bottom">Michalis Sourvinos</credit-words>
|
54 |
+
</credit>
|
55 |
+
<part-list>
|
56 |
+
<part-group type="start" number="1">
|
57 |
+
<group-symbol>none</group-symbol>
|
58 |
+
</part-group>
|
59 |
+
<score-part id="P1">
|
60 |
+
<part-name>Classical Guitar</part-name>
|
61 |
+
<part-abbreviation>Guit.</part-abbreviation>
|
62 |
+
<score-instrument id="P1-I1">
|
63 |
+
<instrument-name>Classical Guitar</instrument-name>
|
64 |
+
</score-instrument>
|
65 |
+
<midi-device id="P1-I1" port="1"></midi-device>
|
66 |
+
<midi-instrument id="P1-I1">
|
67 |
+
<midi-channel>1</midi-channel>
|
68 |
+
<midi-program>25</midi-program>
|
69 |
+
<volume>78.7402</volume>
|
70 |
+
<pan>0</pan>
|
71 |
+
</midi-instrument>
|
72 |
+
</score-part>
|
73 |
+
<part-group type="stop" number="1"/>
|
74 |
+
</part-list>
|
75 |
+
<part id="P1">
|
76 |
+
<measure number="0" implicit="yes" width="389.07">
|
77 |
+
<print>
|
78 |
+
<system-layout>
|
79 |
+
<system-margins>
|
80 |
+
<left-margin>50.00</left-margin>
|
81 |
+
<right-margin>0.00</right-margin>
|
82 |
+
</system-margins>
|
83 |
+
<top-system-distance>170.00</top-system-distance>
|
84 |
+
</system-layout>
|
85 |
+
<staff-layout number="2">
|
86 |
+
<staff-distance>130.23</staff-distance>
|
87 |
+
</staff-layout>
|
88 |
+
</print>
|
89 |
+
<attributes>
|
90 |
+
<divisions>4</divisions>
|
91 |
+
<key>
|
92 |
+
<fifths>3</fifths>
|
93 |
+
</key>
|
94 |
+
<time>
|
95 |
+
<beats>2</beats>
|
96 |
+
<beat-type>4</beat-type>
|
97 |
+
</time>
|
98 |
+
<staves>2</staves>
|
99 |
+
<clef number="1">
|
100 |
+
<sign>G</sign>
|
101 |
+
<line>2</line>
|
102 |
+
<clef-octave-change>-1</clef-octave-change>
|
103 |
+
</clef>
|
104 |
+
<clef number="2">
|
105 |
+
<sign>TAB</sign>
|
106 |
+
<line>5</line>
|
107 |
+
</clef>
|
108 |
+
<staff-details number="2">
|
109 |
+
<staff-lines>6</staff-lines>
|
110 |
+
<staff-tuning line="1">
|
111 |
+
<tuning-step>E</tuning-step>
|
112 |
+
<tuning-octave>2</tuning-octave>
|
113 |
+
</staff-tuning>
|
114 |
+
<staff-tuning line="2">
|
115 |
+
<tuning-step>A</tuning-step>
|
116 |
+
<tuning-octave>2</tuning-octave>
|
117 |
+
</staff-tuning>
|
118 |
+
<staff-tuning line="3">
|
119 |
+
<tuning-step>D</tuning-step>
|
120 |
+
<tuning-octave>3</tuning-octave>
|
121 |
+
</staff-tuning>
|
122 |
+
<staff-tuning line="4">
|
123 |
+
<tuning-step>G</tuning-step>
|
124 |
+
<tuning-octave>3</tuning-octave>
|
125 |
+
</staff-tuning>
|
126 |
+
<staff-tuning line="5">
|
127 |
+
<tuning-step>B</tuning-step>
|
128 |
+
<tuning-octave>3</tuning-octave>
|
129 |
+
</staff-tuning>
|
130 |
+
<staff-tuning line="6">
|
131 |
+
<tuning-step>E</tuning-step>
|
132 |
+
<tuning-octave>4</tuning-octave>
|
133 |
+
</staff-tuning>
|
134 |
+
</staff-details>
|
135 |
+
</attributes>
|
136 |
+
<direction placement="above">
|
137 |
+
<direction-type>
|
138 |
+
<metronome parentheses="no" default-x="-37.68" relative-y="20.00">
|
139 |
+
<beat-unit>quarter</beat-unit>
|
140 |
+
<per-minute>60</per-minute>
|
141 |
+
</metronome>
|
142 |
+
</direction-type>
|
143 |
+
<staff>1</staff>
|
144 |
+
<sound tempo="60"/>
|
145 |
+
</direction>
|
146 |
+
<note>
|
147 |
+
<rest/>
|
148 |
+
<duration>2</duration>
|
149 |
+
<voice>1</voice>
|
150 |
+
<type>eighth</type>
|
151 |
+
<staff>1</staff>
|
152 |
+
</note>
|
153 |
+
<note default-x="254.78" default-y="-5.00">
|
154 |
+
<pitch>
|
155 |
+
<step>E</step>
|
156 |
+
<octave>4</octave>
|
157 |
+
</pitch>
|
158 |
+
<duration>2</duration>
|
159 |
+
<voice>1</voice>
|
160 |
+
<type>eighth</type>
|
161 |
+
<stem>down</stem>
|
162 |
+
<staff>1</staff>
|
163 |
+
</note>
|
164 |
+
<backup>
|
165 |
+
<duration>4</duration>
|
166 |
+
</backup>
|
167 |
+
<note>
|
168 |
+
<rest/>
|
169 |
+
<duration>2</duration>
|
170 |
+
<voice>5</voice>
|
171 |
+
<type>eighth</type>
|
172 |
+
<staff>2</staff>
|
173 |
+
</note>
|
174 |
+
<note default-x="257.68" default-y="-170.23">
|
175 |
+
<pitch>
|
176 |
+
<step>E</step>
|
177 |
+
<octave>4</octave>
|
178 |
+
</pitch>
|
179 |
+
<duration>2</duration>
|
180 |
+
<voice>5</voice>
|
181 |
+
<type>eighth</type>
|
182 |
+
<stem>down</stem>
|
183 |
+
<staff>2</staff>
|
184 |
+
<notations>
|
185 |
+
<technical>
|
186 |
+
<string>1</string>
|
187 |
+
<fret>0</fret>
|
188 |
+
</technical>
|
189 |
+
</notations>
|
190 |
+
</note>
|
191 |
+
</measure>
|
192 |
+
<measure number="1" width="589.63">
|
193 |
+
<note default-x="16.50" default-y="30.00">
|
194 |
+
<pitch>
|
195 |
+
<step>E</step>
|
196 |
+
<octave>5</octave>
|
197 |
+
</pitch>
|
198 |
+
<duration>4</duration>
|
199 |
+
<tie type="start"/>
|
200 |
+
<voice>1</voice>
|
201 |
+
<type>quarter</type>
|
202 |
+
<stem>up</stem>
|
203 |
+
<staff>1</staff>
|
204 |
+
<notations>
|
205 |
+
<tied type="start"/>
|
206 |
+
</notations>
|
207 |
+
</note>
|
208 |
+
<note default-x="216.09" default-y="30.00">
|
209 |
+
<pitch>
|
210 |
+
<step>E</step>
|
211 |
+
<octave>5</octave>
|
212 |
+
</pitch>
|
213 |
+
<duration>1</duration>
|
214 |
+
<tie type="stop"/>
|
215 |
+
<voice>1</voice>
|
216 |
+
<type>16th</type>
|
217 |
+
<stem>up</stem>
|
218 |
+
<staff>1</staff>
|
219 |
+
<beam number="1">begin</beam>
|
220 |
+
<beam number="2">begin</beam>
|
221 |
+
<notations>
|
222 |
+
<tied type="stop"/>
|
223 |
+
</notations>
|
224 |
+
</note>
|
225 |
+
<note default-x="306.81" default-y="25.00">
|
226 |
+
<pitch>
|
227 |
+
<step>D</step>
|
228 |
+
<octave>5</octave>
|
229 |
+
</pitch>
|
230 |
+
<duration>1</duration>
|
231 |
+
<voice>1</voice>
|
232 |
+
<type>16th</type>
|
233 |
+
<stem>up</stem>
|
234 |
+
<staff>1</staff>
|
235 |
+
<beam number="1">continue</beam>
|
236 |
+
<beam number="2">continue</beam>
|
237 |
+
</note>
|
238 |
+
<note default-x="397.54" default-y="20.00">
|
239 |
+
<pitch>
|
240 |
+
<step>C</step>
|
241 |
+
<alter>1</alter>
|
242 |
+
<octave>5</octave>
|
243 |
+
</pitch>
|
244 |
+
<duration>1</duration>
|
245 |
+
<voice>1</voice>
|
246 |
+
<type>16th</type>
|
247 |
+
<stem>up</stem>
|
248 |
+
<staff>1</staff>
|
249 |
+
<beam number="1">continue</beam>
|
250 |
+
<beam number="2">continue</beam>
|
251 |
+
</note>
|
252 |
+
<note default-x="488.26" default-y="15.00">
|
253 |
+
<pitch>
|
254 |
+
<step>B</step>
|
255 |
+
<octave>4</octave>
|
256 |
+
</pitch>
|
257 |
+
<duration>1</duration>
|
258 |
+
<voice>1</voice>
|
259 |
+
<type>16th</type>
|
260 |
+
<stem>up</stem>
|
261 |
+
<staff>1</staff>
|
262 |
+
<beam number="1">end</beam>
|
263 |
+
<beam number="2">end</beam>
|
264 |
+
</note>
|
265 |
+
<backup>
|
266 |
+
<duration>8</duration>
|
267 |
+
</backup>
|
268 |
+
<note default-x="16.50" default-y="-60.00">
|
269 |
+
<pitch>
|
270 |
+
<step>A</step>
|
271 |
+
<octave>2</octave>
|
272 |
+
</pitch>
|
273 |
+
<duration>8</duration>
|
274 |
+
<voice>2</voice>
|
275 |
+
<type>half</type>
|
276 |
+
<stem>down</stem>
|
277 |
+
<staff>1</staff>
|
278 |
+
</note>
|
279 |
+
<backup>
|
280 |
+
<duration>8</duration>
|
281 |
+
</backup>
|
282 |
+
<forward>
|
283 |
+
<duration>4</duration>
|
284 |
+
</forward>
|
285 |
+
<note default-x="216.09" default-y="-20.00">
|
286 |
+
<pitch>
|
287 |
+
<step>B</step>
|
288 |
+
<octave>3</octave>
|
289 |
+
</pitch>
|
290 |
+
<duration>4</duration>
|
291 |
+
<voice>4</voice>
|
292 |
+
<type>quarter</type>
|
293 |
+
<stem>down</stem>
|
294 |
+
<staff>1</staff>
|
295 |
+
</note>
|
296 |
+
<note default-x="216.09" default-y="0.00">
|
297 |
+
<chord/>
|
298 |
+
<pitch>
|
299 |
+
<step>F</step>
|
300 |
+
<alter>1</alter>
|
301 |
+
<octave>4</octave>
|
302 |
+
</pitch>
|
303 |
+
<duration>4</duration>
|
304 |
+
<voice>4</voice>
|
305 |
+
<type>quarter</type>
|
306 |
+
<stem>down</stem>
|
307 |
+
<staff>1</staff>
|
308 |
+
</note>
|
309 |
+
<note default-x="216.09" default-y="10.00">
|
310 |
+
<chord/>
|
311 |
+
<pitch>
|
312 |
+
<step>A</step>
|
313 |
+
<octave>4</octave>
|
314 |
+
</pitch>
|
315 |
+
<duration>4</duration>
|
316 |
+
<voice>4</voice>
|
317 |
+
<type>quarter</type>
|
318 |
+
<stem>down</stem>
|
319 |
+
<staff>1</staff>
|
320 |
+
</note>
|
321 |
+
<backup>
|
322 |
+
<duration>8</duration>
|
323 |
+
</backup>
|
324 |
+
<note default-x="14.80" default-y="-170.23">
|
325 |
+
<pitch>
|
326 |
+
<step>E</step>
|
327 |
+
<octave>5</octave>
|
328 |
+
</pitch>
|
329 |
+
<duration>4</duration>
|
330 |
+
<tie type="start"/>
|
331 |
+
<voice>5</voice>
|
332 |
+
<type>quarter</type>
|
333 |
+
<stem>up</stem>
|
334 |
+
<staff>2</staff>
|
335 |
+
<notations>
|
336 |
+
<tied type="start"/>
|
337 |
+
<technical>
|
338 |
+
<string>1</string>
|
339 |
+
<fret>12</fret>
|
340 |
+
</technical>
|
341 |
+
</notations>
|
342 |
+
</note>
|
343 |
+
<note default-x="214.39" default-y="-170.23">
|
344 |
+
<pitch>
|
345 |
+
<step>E</step>
|
346 |
+
<octave>5</octave>
|
347 |
+
</pitch>
|
348 |
+
<duration>1</duration>
|
349 |
+
<tie type="stop"/>
|
350 |
+
<voice>5</voice>
|
351 |
+
<type>16th</type>
|
352 |
+
<stem>up</stem>
|
353 |
+
<staff>2</staff>
|
354 |
+
<beam number="1">begin</beam>
|
355 |
+
<beam number="2">begin</beam>
|
356 |
+
<notations>
|
357 |
+
<tied type="stop"/>
|
358 |
+
<technical>
|
359 |
+
<string>1</string>
|
360 |
+
<fret>12</fret>
|
361 |
+
</technical>
|
362 |
+
</notations>
|
363 |
+
</note>
|
364 |
+
<note default-x="305.11" default-y="-170.23">
|
365 |
+
<pitch>
|
366 |
+
<step>D</step>
|
367 |
+
<octave>5</octave>
|
368 |
+
</pitch>
|
369 |
+
<duration>1</duration>
|
370 |
+
<voice>5</voice>
|
371 |
+
<type>16th</type>
|
372 |
+
<stem>up</stem>
|
373 |
+
<staff>2</staff>
|
374 |
+
<beam number="1">continue</beam>
|
375 |
+
<beam number="2">continue</beam>
|
376 |
+
<notations>
|
377 |
+
<technical>
|
378 |
+
<string>1</string>
|
379 |
+
<fret>10</fret>
|
380 |
+
</technical>
|
381 |
+
</notations>
|
382 |
+
</note>
|
383 |
+
<note default-x="400.44" default-y="-170.23">
|
384 |
+
<pitch>
|
385 |
+
<step>C</step>
|
386 |
+
<alter>1</alter>
|
387 |
+
<octave>5</octave>
|
388 |
+
</pitch>
|
389 |
+
<duration>1</duration>
|
390 |
+
<voice>5</voice>
|
391 |
+
<type>16th</type>
|
392 |
+
<stem>up</stem>
|
393 |
+
<staff>2</staff>
|
394 |
+
<beam number="1">continue</beam>
|
395 |
+
<beam number="2">continue</beam>
|
396 |
+
<notations>
|
397 |
+
<technical>
|
398 |
+
<string>1</string>
|
399 |
+
<fret>9</fret>
|
400 |
+
</technical>
|
401 |
+
</notations>
|
402 |
+
</note>
|
403 |
+
<note default-x="491.16" default-y="-170.23">
|
404 |
+
<pitch>
|
405 |
+
<step>B</step>
|
406 |
+
<octave>4</octave>
|
407 |
+
</pitch>
|
408 |
+
<duration>1</duration>
|
409 |
+
<voice>5</voice>
|
410 |
+
<type>16th</type>
|
411 |
+
<stem>up</stem>
|
412 |
+
<staff>2</staff>
|
413 |
+
<beam number="1">end</beam>
|
414 |
+
<beam number="2">end</beam>
|
415 |
+
<notations>
|
416 |
+
<technical>
|
417 |
+
<string>1</string>
|
418 |
+
<fret>7</fret>
|
419 |
+
</technical>
|
420 |
+
</notations>
|
421 |
+
</note>
|
422 |
+
<backup>
|
423 |
+
<duration>8</duration>
|
424 |
+
</backup>
|
425 |
+
<note default-x="19.40" default-y="-230.23">
|
426 |
+
<pitch>
|
427 |
+
<step>A</step>
|
428 |
+
<octave>2</octave>
|
429 |
+
</pitch>
|
430 |
+
<duration>8</duration>
|
431 |
+
<voice>6</voice>
|
432 |
+
<type>half</type>
|
433 |
+
<stem>down</stem>
|
434 |
+
<staff>2</staff>
|
435 |
+
<notations>
|
436 |
+
<technical>
|
437 |
+
<string>5</string>
|
438 |
+
<fret>0</fret>
|
439 |
+
</technical>
|
440 |
+
</notations>
|
441 |
+
</note>
|
442 |
+
<backup>
|
443 |
+
<duration>8</duration>
|
444 |
+
</backup>
|
445 |
+
<forward>
|
446 |
+
<duration>4</duration>
|
447 |
+
</forward>
|
448 |
+
<note default-x="218.99" default-y="-215.23">
|
449 |
+
<pitch>
|
450 |
+
<step>B</step>
|
451 |
+
<octave>3</octave>
|
452 |
+
</pitch>
|
453 |
+
<duration>4</duration>
|
454 |
+
<voice>8</voice>
|
455 |
+
<type>quarter</type>
|
456 |
+
<stem>down</stem>
|
457 |
+
<staff>2</staff>
|
458 |
+
<notations>
|
459 |
+
<technical>
|
460 |
+
<string>4</string>
|
461 |
+
<fret>9</fret>
|
462 |
+
</technical>
|
463 |
+
</notations>
|
464 |
+
</note>
|
465 |
+
<note default-x="214.39" default-y="-200.23">
|
466 |
+
<chord/>
|
467 |
+
<pitch>
|
468 |
+
<step>F</step>
|
469 |
+
<alter>1</alter>
|
470 |
+
<octave>4</octave>
|
471 |
+
</pitch>
|
472 |
+
<duration>4</duration>
|
473 |
+
<voice>8</voice>
|
474 |
+
<type>quarter</type>
|
475 |
+
<stem>down</stem>
|
476 |
+
<staff>2</staff>
|
477 |
+
<notations>
|
478 |
+
<technical>
|
479 |
+
<string>3</string>
|
480 |
+
<fret>11</fret>
|
481 |
+
</technical>
|
482 |
+
</notations>
|
483 |
+
</note>
|
484 |
+
<note default-x="214.39" default-y="-185.23">
|
485 |
+
<chord/>
|
486 |
+
<pitch>
|
487 |
+
<step>A</step>
|
488 |
+
<octave>4</octave>
|
489 |
+
</pitch>
|
490 |
+
<duration>4</duration>
|
491 |
+
<voice>8</voice>
|
492 |
+
<type>quarter</type>
|
493 |
+
<stem>down</stem>
|
494 |
+
<staff>2</staff>
|
495 |
+
<notations>
|
496 |
+
<technical>
|
497 |
+
<string>2</string>
|
498 |
+
<fret>10</fret>
|
499 |
+
</technical>
|
500 |
+
</notations>
|
501 |
+
</note>
|
502 |
+
<barline location="right">
|
503 |
+
<bar-style>light-heavy</bar-style>
|
504 |
+
</barline>
|
505 |
+
</measure>
|
506 |
+
</part>
|
507 |
+
</score-partwise>
|
frontend/public/guitar-diff-example.vextab.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
tabstave notation=true key=A time=4/4
|
2 |
+
|
3 |
+
notes :q =|: (5/2.5/3.7/4) :8 7-5h6/3 ^3^ 5h6-7/5 ^3^ :q 7V/4 |
|
4 |
+
notes :8 t12p7/4 s5s3/4 :8 3s:16:5-7/5 :q p5/4
|
5 |
+
|
6 |
+
text :w, |#segno, ,|, :hd, , #tr
|
frontend/public/guitarDiffLogo2.svg
ADDED
|
frontend/public/guitarDiffLogo3.svg
ADDED
|
frontend/public/guitar_faded_noReport.png
ADDED
![]() |
frontend/public/guitar_rotated.svg
ADDED
|
frontend/public/guitar_rotated_report.svg
ADDED
|
frontend/public/guitar_straight.svg
ADDED
|
frontend/public/inkscape_canvas.svg
ADDED
|
frontend/public/test.svg
ADDED
|
frontend/public/vite.svg
ADDED
|
frontend/src/App.vue
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { RouterLink, RouterView } from 'vue-router'
|
3 |
+
import { ref } from 'vue'
|
4 |
+
|
5 |
+
const state = ref({
|
6 |
+
position: 'top-right',
|
7 |
+
url: 'https://github.com/xribene',
|
8 |
+
background: '#FFF',
|
9 |
+
fill: '#0a2050',
|
10 |
+
})
|
11 |
+
</script>
|
12 |
+
|
13 |
+
<template>
|
14 |
+
<div class="app-container">
|
15 |
+
<v-github-icon
|
16 |
+
:position="state.position"
|
17 |
+
:url="state.url"
|
18 |
+
:bg-color="state.background"
|
19 |
+
:fill-color="state.fill"
|
20 |
+
/>
|
21 |
+
|
22 |
+
<nav class="navbar">
|
23 |
+
<ul class="nav-list">
|
24 |
+
<li>
|
25 |
+
<RouterLink :to="{ name: 'Home' }">
|
26 |
+
Home
|
27 |
+
</RouterLink>
|
28 |
+
</li>
|
29 |
+
<li>
|
30 |
+
<RouterLink :to="{ name: 'Analyzer' }">
|
31 |
+
Analyzer
|
32 |
+
</RouterLink>
|
33 |
+
</li>
|
34 |
+
</ul>
|
35 |
+
</nav>
|
36 |
+
|
37 |
+
<div class="content">
|
38 |
+
<!-- <a href="https://vitejs.dev" target="_blank">
|
39 |
+
<img src="/guitarDiffLogo2.svg" class="logo" alt="Vite logo" />
|
40 |
+
</a> -->
|
41 |
+
|
42 |
+
<!-- <keep-alive>
|
43 |
+
<router-view />
|
44 |
+
</keep-alive> -->
|
45 |
+
<RouterView v-slot="{ Component }">
|
46 |
+
<keep-alive>
|
47 |
+
<component :is="Component" :key="$route.fullPath" />
|
48 |
+
</keep-alive>
|
49 |
+
</RouterView>
|
50 |
+
</div>
|
51 |
+
</div>
|
52 |
+
</template>
|
53 |
+
|
54 |
+
<style scoped>
|
55 |
+
.app-container {
|
56 |
+
display: flex;
|
57 |
+
flex-direction: column;
|
58 |
+
align-items: center;
|
59 |
+
}
|
60 |
+
|
61 |
+
.navbar {
|
62 |
+
background-color: #c5bdbd;
|
63 |
+
padding: 1rem;
|
64 |
+
width: 100%;
|
65 |
+
/* margin-left: 10px; */
|
66 |
+
}
|
67 |
+
|
68 |
+
.nav-list {
|
69 |
+
list-style: none;
|
70 |
+
padding: 0;
|
71 |
+
margin: 0;
|
72 |
+
display: flex;
|
73 |
+
/* background-color: #0a2050; */
|
74 |
+
}
|
75 |
+
|
76 |
+
.nav-list li {
|
77 |
+
margin-right: 1rem;
|
78 |
+
}
|
79 |
+
|
80 |
+
.nav-list li a {
|
81 |
+
text-decoration: none;
|
82 |
+
color: rgb(78, 74, 74);
|
83 |
+
}
|
84 |
+
|
85 |
+
.content {
|
86 |
+
margin: 2rem;
|
87 |
+
text-align: center;
|
88 |
+
}
|
89 |
+
</style>
|
frontend/src/assets/vue.svg
ADDED
|
frontend/src/components/CounterButton.vue
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { ref } from 'vue'
|
3 |
+
|
4 |
+
defineProps({
|
5 |
+
msg: String,
|
6 |
+
})
|
7 |
+
|
8 |
+
const counter = ref(0)
|
9 |
+
|
10 |
+
function increment() {
|
11 |
+
counter.value++
|
12 |
+
}
|
13 |
+
</script>
|
14 |
+
|
15 |
+
<template>
|
16 |
+
<h1>{{ msg }}</h1>
|
17 |
+
<button @click="increment">
|
18 |
+
{{ counter }}
|
19 |
+
</button>
|
20 |
+
</template>
|
frontend/src/components/HelloWorld.vue
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { ref } from 'vue'
|
3 |
+
|
4 |
+
defineProps({
|
5 |
+
msg: String,
|
6 |
+
})
|
7 |
+
|
8 |
+
const count = ref(0)
|
9 |
+
</script>
|
10 |
+
|
11 |
+
<template>
|
12 |
+
<h1>{{ msg }}</h1>
|
13 |
+
|
14 |
+
<div class="card">
|
15 |
+
<button type="button" @click="count++">
|
16 |
+
count is {{ count }}
|
17 |
+
</button>
|
18 |
+
<p>
|
19 |
+
Edit
|
20 |
+
<code>components/HelloWorld.vue</code> to test HMR
|
21 |
+
</p>
|
22 |
+
</div>
|
23 |
+
|
24 |
+
<p>
|
25 |
+
Check out
|
26 |
+
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite starter
|
27 |
+
</p>
|
28 |
+
<p>
|
29 |
+
Install
|
30 |
+
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
|
31 |
+
in your IDE for a better DX
|
32 |
+
</p>
|
33 |
+
<p class="read-the-docs">
|
34 |
+
Click on the Vite and Vue logos to learn more
|
35 |
+
</p>
|
36 |
+
</template>
|
37 |
+
|
38 |
+
<style scoped>
|
39 |
+
.read-the-docs {
|
40 |
+
color: #888;
|
41 |
+
}
|
42 |
+
</style>
|
frontend/src/components/MusicXmlWidget.vue
ADDED
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { computed, onMounted, onUpdated, ref, watch } from 'vue'
|
3 |
+
import { OpenSheetMusicDisplay } from 'opensheetmusicdisplay'
|
4 |
+
import { Pane } from 'tweakpane'
|
5 |
+
|
6 |
+
const props = defineProps({
|
7 |
+
// int id
|
8 |
+
id: {
|
9 |
+
type: String,
|
10 |
+
required: true,
|
11 |
+
},
|
12 |
+
xmlText: {
|
13 |
+
type: String,
|
14 |
+
required: false,
|
15 |
+
},
|
16 |
+
isActive: {
|
17 |
+
type: Boolean,
|
18 |
+
required: false,
|
19 |
+
default: false,
|
20 |
+
},
|
21 |
+
|
22 |
+
})
|
23 |
+
|
24 |
+
const emit = defineEmits(['updateScoreCode'])
|
25 |
+
|
26 |
+
// let renderer = null;
|
27 |
+
// let artist = null;
|
28 |
+
// let tab = null;
|
29 |
+
|
30 |
+
let openSheetMusicDisplay = null
|
31 |
+
let timeoutID = null
|
32 |
+
let pane = null
|
33 |
+
|
34 |
+
// const message = ref('hello')
|
35 |
+
const currentScoreCode = ref(props.xmlText)
|
36 |
+
const showParsingError = ref(false)
|
37 |
+
const parsingError = ref('')
|
38 |
+
// const count = ref(0)
|
39 |
+
const settingsStatus = ref(false)
|
40 |
+
const isActive = ref(false)
|
41 |
+
|
42 |
+
const SETTINGS_PARAMS = {
|
43 |
+
scale: 1.0,
|
44 |
+
// width: 800,
|
45 |
+
// factor: 123,
|
46 |
+
// title: 'hello',
|
47 |
+
// color: '#ff0055',
|
48 |
+
// percentage: 50,
|
49 |
+
// theme: 'dark',
|
50 |
+
// prop: 'Put your\nmultiline\ntext here!'
|
51 |
+
}
|
52 |
+
|
53 |
+
const divId = computed(() => {
|
54 |
+
return `xmlScoreContainer_${props.id}`
|
55 |
+
})
|
56 |
+
|
57 |
+
function initializePane() {
|
58 |
+
pane = new Pane({
|
59 |
+
container: document.getElementById('paneContainerXml'),
|
60 |
+
title: 'MusicXML Settings',
|
61 |
+
},
|
62 |
+
)
|
63 |
+
pane.addBinding(SETTINGS_PARAMS, 'scale', {
|
64 |
+
min: 0.5,
|
65 |
+
max: 2.0,
|
66 |
+
step: 0.1,
|
67 |
+
}).on('change', (ev) => {
|
68 |
+
console.log(ev.value)
|
69 |
+
openSheetMusicDisplay.zoom = ev.value
|
70 |
+
openSheetMusicDisplay.render()
|
71 |
+
})
|
72 |
+
|
73 |
+
// pane.addBinding(SETTINGS_PARAMS, 'width', {
|
74 |
+
// min: 400,
|
75 |
+
// max: 1200,
|
76 |
+
// step: 50
|
77 |
+
// }).on('change', (ev) => {
|
78 |
+
// console.log(ev.value);
|
79 |
+
// artist.reset();
|
80 |
+
// tab.reset();
|
81 |
+
// tab.parse(currentTabText.value);
|
82 |
+
// artist.width = ev.value;
|
83 |
+
// artist.render(renderer);
|
84 |
+
// });
|
85 |
+
}
|
86 |
+
async function initializeOSMD() {
|
87 |
+
// renderer = new Flow.Renderer($('#' + divId.value)[0], Flow.Renderer.Backends.SVG);
|
88 |
+
// artist = new Artist(10, 10, 750, { scale: 0.8 });
|
89 |
+
// tab = new VexTab(artist);
|
90 |
+
openSheetMusicDisplay = new OpenSheetMusicDisplay(divId.value, {
|
91 |
+
autoResize: false,
|
92 |
+
backend: 'svg',
|
93 |
+
disableCursor: false,
|
94 |
+
drawingParameters: 'full', // : "default", // try compact (instead of default)
|
95 |
+
drawPartNames: false, // try false
|
96 |
+
drawTitle: false,
|
97 |
+
drawSubtitle: false,
|
98 |
+
drawComposer: false,
|
99 |
+
// darkMode: true,
|
100 |
+
// cursor
|
101 |
+
followCursor: true,
|
102 |
+
drawFingerings: true,
|
103 |
+
// fingeringPosition: "left", // Above/Below is default. try left or right. experimental: above, below.
|
104 |
+
// fingeringPositionFromXML: false, // do this if you want them always left, for example.
|
105 |
+
// fingeringInsideStafflines: "true", // default: false. true draws fingerings directly above/below notes
|
106 |
+
setWantedStemDirectionByXml: true, // try false, which was previously the default behavior
|
107 |
+
drawUpToMeasureNumber: 20, // draws only up to measure 3, meaning it draws measure 1 to 3 of the piece.
|
108 |
+
// drawFromMeasureNumber : 1,
|
109 |
+
// drawUpToMeasureNumber : 3,
|
110 |
+
drawMeasureNumbers: true,
|
111 |
+
|
112 |
+
// drawMeasureNumbers: false, // disable drawing measure numbers
|
113 |
+
// measureNumberInterval: 4, // draw measure numbers only every 4 bars (and at the beginning of a new system)
|
114 |
+
useXMLMeasureNumbers: true, // read measure numbers from xml
|
115 |
+
|
116 |
+
// coloring options
|
117 |
+
coloringEnabled: true,
|
118 |
+
// defaultColorNotehead: "#CC0055", // try setting a default color. default is black (undefined)
|
119 |
+
// defaultColorStem: "#BB0099",
|
120 |
+
|
121 |
+
autoBeam: false, // try true, OSMD Function Test AutoBeam sample
|
122 |
+
autoBeamOptions: {
|
123 |
+
beam_rests: false,
|
124 |
+
beam_middle_rests_only: false,
|
125 |
+
// groups: [[3,4], [1,1]],
|
126 |
+
maintain_stem_directions: false,
|
127 |
+
},
|
128 |
+
// pageFormat: "A4_P",//"Endless",//pageFormat,
|
129 |
+
// pageBackgroundColor: "red",
|
130 |
+
renderSingleHorizontalStaffline: true, // true
|
131 |
+
|
132 |
+
// tupletsBracketed: true, // creates brackets for all tuplets except triplets, even when not set by xml
|
133 |
+
// tripletsBracketed: true,
|
134 |
+
// tupletsRatioed: true, // unconventional; renders ratios for tuplets (3:2 instead of 3 for triplets)
|
135 |
+
})
|
136 |
+
// window.osmd = openSheetMusicDisplay;
|
137 |
+
// artist.reset();
|
138 |
+
// tab.reset();
|
139 |
+
// tab.parse(currentTabText.value);
|
140 |
+
// artist.render(renderer);
|
141 |
+
await fetch('/guitar-diff-example.musicxml')
|
142 |
+
.then((response) => {
|
143 |
+
return response.text()
|
144 |
+
})
|
145 |
+
.then((data) => {
|
146 |
+
console.log('in data')
|
147 |
+
openSheetMusicDisplay.load(data)
|
148 |
+
.then(
|
149 |
+
() => {
|
150 |
+
window.osmd = openSheetMusicDisplay
|
151 |
+
openSheetMusicDisplay.render()
|
152 |
+
// openSheetMusicDisplay.cursor.show();
|
153 |
+
console.log('in load')
|
154 |
+
showParsingError.value = false
|
155 |
+
currentScoreCode.value = data
|
156 |
+
},
|
157 |
+
)
|
158 |
+
.catch((e) => {
|
159 |
+
showParsingError.value = true
|
160 |
+
console.log(e.message.replace(/(?:\r\n|\r|\n)/g, '<br>'))
|
161 |
+
parsingError.value = e.message.replace(/(?:\r\n|\r|\n)/g, '<br>')
|
162 |
+
})
|
163 |
+
|
164 |
+
// .catch((e) => {
|
165 |
+
// showParsingError.value = true;
|
166 |
+
// console.log(e.message.replace(/(?:\r\n|\r|\n)/g, '<br>'));
|
167 |
+
// parsingError.value = e.message.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
168 |
+
// });
|
169 |
+
})
|
170 |
+
}
|
171 |
+
|
172 |
+
// function loadScoreCode(scoreCode) {
|
173 |
+
// currentScoreCode.value = scoreCode
|
174 |
+
// showScore()
|
175 |
+
// }
|
176 |
+
|
177 |
+
function showScore() {
|
178 |
+
openSheetMusicDisplay.clear()
|
179 |
+
console.log(currentScoreCode.value)
|
180 |
+
openSheetMusicDisplay.load(currentScoreCode.value)
|
181 |
+
.then(
|
182 |
+
() => {
|
183 |
+
window.osmd = openSheetMusicDisplay
|
184 |
+
openSheetMusicDisplay.render()
|
185 |
+
// openSheetMusicDisplay.cursor.show();
|
186 |
+
console.log('in load')
|
187 |
+
showParsingError.value = false
|
188 |
+
},
|
189 |
+
)
|
190 |
+
.catch((e) => {
|
191 |
+
showParsingError.value = true
|
192 |
+
console.log(e.message.replace(/(?:\r\n|\r|\n)/g, '<br>'))
|
193 |
+
parsingError.value = e.message.replace(/(?:\r\n|\r|\n)/g, '<br>')
|
194 |
+
})
|
195 |
+
}
|
196 |
+
|
197 |
+
function handleKeyUp(_event) {
|
198 |
+
if (timeoutID)
|
199 |
+
clearTimeout(timeoutID)
|
200 |
+
timeoutID = setTimeout(showScore, 500)
|
201 |
+
}
|
202 |
+
|
203 |
+
onMounted(async () => {
|
204 |
+
// console.log($(`#${divId.value}`)[0])
|
205 |
+
initializePane()
|
206 |
+
await initializeOSMD()
|
207 |
+
})
|
208 |
+
|
209 |
+
function handleDrop(event) {
|
210 |
+
event.preventDefault()
|
211 |
+
const textData = event.dataTransfer.getData('text')
|
212 |
+
const file = event.dataTransfer.files[0]
|
213 |
+
console.log(textData)
|
214 |
+
console.log(file)
|
215 |
+
if (file) {
|
216 |
+
const reader = new FileReader()
|
217 |
+
reader.onload = function (e) {
|
218 |
+
currentScoreCode.value = e.target.result
|
219 |
+
showScore()
|
220 |
+
}
|
221 |
+
reader.readAsText(file)
|
222 |
+
}
|
223 |
+
else if (textData) {
|
224 |
+
currentScoreCode.value = textData
|
225 |
+
showScore()
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
function showHideSettings() {
|
230 |
+
console.log('showHideSettings')
|
231 |
+
settingsStatus.value = !settingsStatus.value
|
232 |
+
}
|
233 |
+
|
234 |
+
// invoked when there is any type of change in the component
|
235 |
+
onUpdated(() => {
|
236 |
+
if (props.isActive !== isActive.value) {
|
237 |
+
// Prop has changed, update the ref and emit an event
|
238 |
+
if (props.isActive) {
|
239 |
+
isActive.value = props.isActive
|
240 |
+
emit('updateScoreCode', currentScoreCode.value)
|
241 |
+
// console.log("emitted updateScoreCode");
|
242 |
+
// console.log(currentScoreCode.value);
|
243 |
+
}
|
244 |
+
isActive.value = props.isActive
|
245 |
+
}
|
246 |
+
})
|
247 |
+
|
248 |
+
watch(currentScoreCode, () => {
|
249 |
+
// Emit the event so that the parent component can update the tabText
|
250 |
+
// prop
|
251 |
+
emit('updateScoreCode', currentScoreCode.value)
|
252 |
+
// console.log("emitted updateScoreCode");
|
253 |
+
// console.log(currentScoreCode.value);
|
254 |
+
})
|
255 |
+
|
256 |
+
// const moveCursor = () => {
|
257 |
+
// openSheetMusicDisplay.cursor.next();
|
258 |
+
// };
|
259 |
+
|
260 |
+
// const fillScore = () => {
|
261 |
+
// // console.log(vt);
|
262 |
+
// // Perform any logic to fill the score
|
263 |
+
// response.value = 'Button pressed!'; // Update response if needed
|
264 |
+
|
265 |
+
// };
|
266 |
+
</script>
|
267 |
+
|
268 |
+
<template>
|
269 |
+
<!--
|
270 |
+
Which ever of the following elements wants to use the class
|
271 |
+
attributes coming from the parent component needs to use
|
272 |
+
:class="$attrs.class"
|
273 |
+
UNLESS I have a single root div-element
|
274 |
+
-->
|
275 |
+
<div>
|
276 |
+
<!-- <button @click="showScore">You clicked me {{ count }} times</button> -->
|
277 |
+
<button class="left-align" @click="showHideSettings">
|
278 |
+
<!-- <v-icon icon="mdi-pencil-box" /> -->
|
279 |
+
Settings
|
280 |
+
</button>
|
281 |
+
<div :id="divId" class="scoreContainer" />
|
282 |
+
|
283 |
+
<div v-show="settingsStatus" id="tabSettingsArea">
|
284 |
+
<!-- <TweakComponent :visible="settingsStatus"/> -->
|
285 |
+
<div id="paneContainerXml" />
|
286 |
+
<textarea
|
287 |
+
v-model="currentScoreCode"
|
288 |
+
class="editorBox"
|
289 |
+
placeholder="add your musicxml code here or drag a file"
|
290 |
+
@keyup="handleKeyUp"
|
291 |
+
@drop="handleDrop"
|
292 |
+
@dragover.prevent
|
293 |
+
/>
|
294 |
+
</div>
|
295 |
+
|
296 |
+
<div v-if="showParsingError" class="parsing-error" v-html="parsingError" />
|
297 |
+
</div>
|
298 |
+
</template>
|
299 |
+
|
300 |
+
<style scoped>
|
301 |
+
.xmlContainer {
|
302 |
+
/* width: 100%;
|
303 |
+
height: 100%; */
|
304 |
+
/* background-color: #f80707; */
|
305 |
+
border: 0px solid rgb(212, 22, 22);
|
306 |
+
overflow-x: auto;
|
307 |
+
}
|
308 |
+
|
309 |
+
.left-align {
|
310 |
+
display: flex;
|
311 |
+
margin-right: auto;
|
312 |
+
}
|
313 |
+
#tabSettingsArea {
|
314 |
+
display: flex;
|
315 |
+
flex-direction: row;
|
316 |
+
align-items: center; /* Optional: align items in the center vertically */
|
317 |
+
gap: 20px;
|
318 |
+
margin-left: 10px;
|
319 |
+
}
|
320 |
+
</style>
|
frontend/src/components/TweakComponent.vue
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script>
|
2 |
+
import { ref } from 'vue'
|
3 |
+
|
4 |
+
const state = ref({
|
5 |
+
pane: {
|
6 |
+
title: 'My Awesome Pane',
|
7 |
+
inputs: [
|
8 |
+
{
|
9 |
+
factor: 123,
|
10 |
+
title: 'hello',
|
11 |
+
color: '#0f0',
|
12 |
+
},
|
13 |
+
],
|
14 |
+
},
|
15 |
+
})
|
16 |
+
const skata = 3
|
17 |
+
</script>
|
18 |
+
|
19 |
+
<template>
|
20 |
+
<!-- <v-tweakpane :pane="state.pane" /> -->
|
21 |
+
<div>blabla</div>
|
22 |
+
</template>
|
23 |
+
|
24 |
+
<style>
|
25 |
+
@import 'v-tweakpane/dist/v-tweakpane.css';
|
26 |
+
</style>
|
frontend/src/components/TweakComponent2.vue
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { Pane } from 'tweakpane'
|
3 |
+
import * as TextareaPlugin from '@pangenerator/tweakpane-textarea-plugin'
|
4 |
+
import { onMounted, watch } from 'vue'
|
5 |
+
|
6 |
+
const props = defineProps({
|
7 |
+
visible: {
|
8 |
+
type: Boolean,
|
9 |
+
required: false,
|
10 |
+
default: false,
|
11 |
+
},
|
12 |
+
data: {
|
13 |
+
type: Object,
|
14 |
+
required: true,
|
15 |
+
default: () => {},
|
16 |
+
},
|
17 |
+
})
|
18 |
+
|
19 |
+
let pane = null
|
20 |
+
|
21 |
+
onMounted(() => {
|
22 |
+
initializePane()
|
23 |
+
})
|
24 |
+
|
25 |
+
watch(() => props.visible, () => {
|
26 |
+
updateVisibility()
|
27 |
+
})
|
28 |
+
|
29 |
+
// const updateData = (changeEvent) => {
|
30 |
+
// console.log(changeEvent);
|
31 |
+
// };
|
32 |
+
|
33 |
+
// const showHide = () => {
|
34 |
+
// pane.hidden = !pane.hidden;
|
35 |
+
// };
|
36 |
+
|
37 |
+
function updateVisibility() {
|
38 |
+
if (pane)
|
39 |
+
pane.hidden = !props.visible
|
40 |
+
}
|
41 |
+
|
42 |
+
function initializePane() {
|
43 |
+
const PARAMS = {
|
44 |
+
factor: 123,
|
45 |
+
title: 'hello',
|
46 |
+
color: '#ff0055',
|
47 |
+
percentage: 50,
|
48 |
+
theme: 'dark',
|
49 |
+
prop: 'Put your\nmultiline\ntext here!',
|
50 |
+
}
|
51 |
+
|
52 |
+
pane = new Pane({
|
53 |
+
container: document.getElementById('paneContainer'),
|
54 |
+
title: 'Mixer',
|
55 |
+
},
|
56 |
+
)
|
57 |
+
pane.registerPlugin(TextareaPlugin)
|
58 |
+
|
59 |
+
pane.addBinding(PARAMS, 'factor')
|
60 |
+
pane.addBinding(PARAMS, 'title')
|
61 |
+
pane.addBinding(PARAMS, 'color')
|
62 |
+
pane.addBinding(
|
63 |
+
PARAMS,
|
64 |
+
'percentage',
|
65 |
+
{ min: 0, max: 100, step: 10 },
|
66 |
+
)
|
67 |
+
|
68 |
+
// `options`: list
|
69 |
+
pane.addBinding(
|
70 |
+
PARAMS,
|
71 |
+
'theme',
|
72 |
+
{ options: { Dark: 'dark', Light: 'light' } },
|
73 |
+
)
|
74 |
+
|
75 |
+
// multiline pluggin
|
76 |
+
|
77 |
+
// pane.addBinding(PARAMS, 'prop', {
|
78 |
+
// view: 'textarea',
|
79 |
+
// rows: 6,
|
80 |
+
// placeholder: 'Type here...'
|
81 |
+
// }).on('change', (ev) => {
|
82 |
+
// console.log(ev.value);
|
83 |
+
// });
|
84 |
+
|
85 |
+
pane.hidden = !props.visible
|
86 |
+
}
|
87 |
+
</script>
|
88 |
+
|
89 |
+
<template>
|
90 |
+
<div id="paneContainer" />
|
91 |
+
</template>
|
92 |
+
|
93 |
+
<style scoped>
|
94 |
+
#paneContainer2 {
|
95 |
+
position: absolute;
|
96 |
+
top:300px;
|
97 |
+
right: 100px;
|
98 |
+
|
99 |
+
/* top: 0px; */
|
100 |
+
/* left: 0px; */
|
101 |
+
/* width: 100%; */
|
102 |
+
/* height: 100%; */
|
103 |
+
/* background-color: #f80707; */
|
104 |
+
/* border: 1px solid black; */
|
105 |
+
/* overflow-x: scroll; */
|
106 |
+
}
|
107 |
+
</style>
|
frontend/src/components/VextabWidget.vue
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { computed, onMounted, onUpdated, ref, watch } from 'vue'
|
3 |
+
import { Artist, Flow, VexTab } from 'vextab/releases/vextab-div.js'
|
4 |
+
|
5 |
+
// import TweakComponent from '@/components/TweakComponent2.vue'
|
6 |
+
import { Pane } from 'tweakpane'
|
7 |
+
import * as TextareaPlugin from '@pangenerator/tweakpane-textarea-plugin'
|
8 |
+
|
9 |
+
const props = defineProps({
|
10 |
+
// int id
|
11 |
+
id: {
|
12 |
+
type: String,
|
13 |
+
required: true,
|
14 |
+
},
|
15 |
+
tabText: {
|
16 |
+
type: String,
|
17 |
+
required: false,
|
18 |
+
},
|
19 |
+
isActive: {
|
20 |
+
type: Boolean,
|
21 |
+
required: false,
|
22 |
+
default: false,
|
23 |
+
},
|
24 |
+
|
25 |
+
})
|
26 |
+
|
27 |
+
const emit = defineEmits(['updateScoreCode'])
|
28 |
+
|
29 |
+
let renderer = null
|
30 |
+
let artist = null
|
31 |
+
let tab = null
|
32 |
+
let timeoutID = null
|
33 |
+
let pane = null
|
34 |
+
|
35 |
+
const SETTINGS_PARAMS = {
|
36 |
+
scale: 1.0,
|
37 |
+
width: 800,
|
38 |
+
// factor: 123,
|
39 |
+
// title: 'hello',
|
40 |
+
// color: '#ff0055',
|
41 |
+
// percentage: 50,
|
42 |
+
// theme: 'dark',
|
43 |
+
// prop: 'Put your\nmultiline\ntext here!'
|
44 |
+
}
|
45 |
+
|
46 |
+
const message = ref('hello')
|
47 |
+
const currentScoreCode = ref(props.tabText)
|
48 |
+
const showParsingError = ref(false)
|
49 |
+
const parsingError = ref('')
|
50 |
+
const count = ref(0)
|
51 |
+
const settingsStatus = ref(false)
|
52 |
+
const isActive = ref(props.isActive)
|
53 |
+
|
54 |
+
const scoreRef = ref(null)
|
55 |
+
const paneContainer = ref(null)
|
56 |
+
const divId = computed(() => {
|
57 |
+
console.log('inside computed')
|
58 |
+
return `scoreContainer_${props.id}`
|
59 |
+
})
|
60 |
+
|
61 |
+
onMounted(() => {
|
62 |
+
// console.log($(`#${divId.value}`)[0])
|
63 |
+
console.log('mounted start')
|
64 |
+
initializePane()
|
65 |
+
initializeVexTab()
|
66 |
+
console.log('mounted end')
|
67 |
+
})
|
68 |
+
|
69 |
+
function initializeVexTab() {
|
70 |
+
// renderer = new Flow.Renderer($(`#${divId.value}`)[0], Flow.Renderer.Backends.SVG)
|
71 |
+
renderer = new Flow.Renderer(scoreRef.value, Flow.Renderer.Backends.SVG)
|
72 |
+
artist = new Artist(10, 10, SETTINGS_PARAMS.width, { scale: SETTINGS_PARAMS.scale })
|
73 |
+
tab = new VexTab(artist)
|
74 |
+
showScore()
|
75 |
+
}
|
76 |
+
function initializePane() {
|
77 |
+
pane = new Pane({
|
78 |
+
container: paneContainer.value,
|
79 |
+
title: 'VexTab Settings',
|
80 |
+
},
|
81 |
+
)
|
82 |
+
pane.registerPlugin(TextareaPlugin)
|
83 |
+
pane.addBinding(SETTINGS_PARAMS, 'scale', {
|
84 |
+
min: 0.5,
|
85 |
+
max: 2.0,
|
86 |
+
step: 0.1,
|
87 |
+
}).on('change', (ev) => {
|
88 |
+
console.log(ev.value)
|
89 |
+
artist.reset()
|
90 |
+
tab.reset()
|
91 |
+
tab.parse(currentScoreCode.value)
|
92 |
+
artist.options.scale = ev.value
|
93 |
+
artist.render(renderer)
|
94 |
+
})
|
95 |
+
|
96 |
+
pane.addBinding(SETTINGS_PARAMS, 'width', {
|
97 |
+
min: 400,
|
98 |
+
max: 1200,
|
99 |
+
step: 50,
|
100 |
+
}).on('change', (ev) => {
|
101 |
+
console.log(ev.value)
|
102 |
+
artist.reset()
|
103 |
+
tab.reset()
|
104 |
+
tab.parse(currentScoreCode.value)
|
105 |
+
artist.width = ev.value
|
106 |
+
artist.render(renderer)
|
107 |
+
})
|
108 |
+
}
|
109 |
+
|
110 |
+
function showScore() {
|
111 |
+
try {
|
112 |
+
artist.reset()
|
113 |
+
tab.reset()
|
114 |
+
tab.parse(currentScoreCode.value)
|
115 |
+
|
116 |
+
// artist.width += 100;
|
117 |
+
artist.render(renderer)
|
118 |
+
console.log('test')
|
119 |
+
console.log(artist.width)
|
120 |
+
showParsingError.value = false
|
121 |
+
}
|
122 |
+
catch (e) {
|
123 |
+
showParsingError.value = true
|
124 |
+
console.log(e.message.replace(/(?:\r\n|\r|\n)/g, '<br>'))
|
125 |
+
parsingError.value = e.message.replace(/(?:\r\n|\r|\n)/g, '<br>')
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
function handleKeyUp(event) {
|
130 |
+
if (timeoutID)
|
131 |
+
clearTimeout(timeoutID)
|
132 |
+
timeoutID = setTimeout(showScore, 500)
|
133 |
+
}
|
134 |
+
|
135 |
+
function handleDrop(event) {
|
136 |
+
event.preventDefault()
|
137 |
+
const textData = event.dataTransfer.getData('text')
|
138 |
+
const file = event.dataTransfer.files[0]
|
139 |
+
console.log(textData)
|
140 |
+
console.log(file)
|
141 |
+
if (file) {
|
142 |
+
const reader = new FileReader()
|
143 |
+
reader.onload = function (e) {
|
144 |
+
currentScoreCode.value = e.target.result
|
145 |
+
showScore()
|
146 |
+
}
|
147 |
+
reader.readAsText(file)
|
148 |
+
}
|
149 |
+
else if (textData) {
|
150 |
+
currentScoreCode.value = textData
|
151 |
+
showScore()
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
function showHideSettings() {
|
156 |
+
console.log('showHideSettings')
|
157 |
+
settingsStatus.value = !settingsStatus.value
|
158 |
+
}
|
159 |
+
|
160 |
+
// invoked when there is any type of change in the component
|
161 |
+
onUpdated(() => {
|
162 |
+
if (props.isActive !== isActive.value) {
|
163 |
+
// Prop has changed, update the ref and emit an event
|
164 |
+
if (props.isActive) {
|
165 |
+
isActive.value = props.isActive
|
166 |
+
emit('updateScoreCode', currentScoreCode.value)
|
167 |
+
console.log('emitted updateScoreCode')
|
168 |
+
}
|
169 |
+
isActive.value = props.isActive
|
170 |
+
}
|
171 |
+
})
|
172 |
+
|
173 |
+
watch(currentScoreCode, () => {
|
174 |
+
// Emit the event so that the parent component can update the tabText
|
175 |
+
// prop
|
176 |
+
emit('updateScoreCode', currentScoreCode.value)
|
177 |
+
console.log('emitted updateScoreCode')
|
178 |
+
// this should go to the first tab that is shown (for now vextab)
|
179 |
+
}, { immediate: true })
|
180 |
+
</script>
|
181 |
+
|
182 |
+
<template>
|
183 |
+
<!--
|
184 |
+
Which ever of the following elements wants to use the class
|
185 |
+
attributes coming from the parent component needs to use
|
186 |
+
:class="$attrs.class"
|
187 |
+
UNLESS I have a single root div-element
|
188 |
+
-->
|
189 |
+
<div>
|
190 |
+
<!-- <button class="left-align i-twemoji:globe-showing-europe-africa" @click="showHideSettings">
|
191 |
+
Settings
|
192 |
+
</button> -->
|
193 |
+
<button class="i-mdi:file-document-edit-outline?mask flex text-3xl text-stone-700" @click="showHideSettings" />
|
194 |
+
<!-- <div class="mt-4 w-full flex items-center justify-center gap-x-4 p-2 text-4xl">
|
195 |
+
<button class="i-vscode:file-type-light-pnpm" />
|
196 |
+
<button class="i-vscode:file-type-light-pnpm?mask text-red-300" />
|
197 |
+
</div> -->
|
198 |
+
<div :id="divId" ref="scoreRef" class="scoreContainer" />
|
199 |
+
<div v-show="settingsStatus" class="tabSettingsArea">
|
200 |
+
<div ref="paneContainer" class="basis-3/12" />
|
201 |
+
<textarea
|
202 |
+
v-show="settingsStatus" v-model="currentScoreCode"
|
203 |
+
class="editorBox justify-center"
|
204 |
+
placeholder="add your vextab code here or drag a file"
|
205 |
+
@keyup="handleKeyUp"
|
206 |
+
@drop="handleDrop"
|
207 |
+
@dragover.prevent
|
208 |
+
/>
|
209 |
+
</div>
|
210 |
+
|
211 |
+
<div v-if="showParsingError" class="ml-10px mt-10px text-red-500" v-html="parsingError" />
|
212 |
+
</div>
|
213 |
+
</template>
|
214 |
+
|
215 |
+
<style scoped>
|
216 |
+
.tabSettingsArea {
|
217 |
+
display: flex;
|
218 |
+
/* flex-direction: row; */
|
219 |
+
align-items: center;
|
220 |
+
justify-content: center;
|
221 |
+
|
222 |
+
gap: 20px;
|
223 |
+
margin-left: 10px;
|
224 |
+
}
|
225 |
+
</style>
|
frontend/src/main.js
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createApp } from 'vue'
|
2 |
+
import { Tab, Tabs } from 'vue3-tabs-component'
|
3 |
+
import { VGithubIcon } from 'v-github-icon'
|
4 |
+
import { router } from '@/plugins/router'
|
5 |
+
import '@/style.css'
|
6 |
+
import App from '@/App.vue'
|
7 |
+
|
8 |
+
// import { createMetaManager } from 'vue-meta'
|
9 |
+
import 'virtual:uno.css'
|
10 |
+
|
11 |
+
// Vuetify
|
12 |
+
// import 'vuetify/styles'
|
13 |
+
// import { createVuetify } from 'vuetify'
|
14 |
+
// import * as components from 'vuetify/components'
|
15 |
+
// import * as directives from 'vuetify/directives'
|
16 |
+
// import { aliases, mdi } from 'vuetify/iconsets/mdi'
|
17 |
+
// import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader
|
18 |
+
|
19 |
+
// const vuetify = createVuetify({
|
20 |
+
// components,
|
21 |
+
// directives,
|
22 |
+
// // icons: {
|
23 |
+
// // defaultSet: 'mdi',
|
24 |
+
// // aliases,
|
25 |
+
// // sets: {
|
26 |
+
// // mdi,
|
27 |
+
// // },
|
28 |
+
// // },
|
29 |
+
// icons: {
|
30 |
+
// defaultSet: 'mdi', // This is already the default value - only for display purposes
|
31 |
+
// },
|
32 |
+
// defaults: {
|
33 |
+
// VBtn: {
|
34 |
+
// color: 'primary',
|
35 |
+
// variant: 'outlined',
|
36 |
+
// rounded: true,
|
37 |
+
// },
|
38 |
+
// },
|
39 |
+
// })
|
40 |
+
|
41 |
+
const app = createApp(App)
|
42 |
+
.use(router)
|
43 |
+
// .use(store)
|
44 |
+
// .use(vuetify)
|
45 |
+
.component('tabs', Tabs)
|
46 |
+
.component('tab', Tab)
|
47 |
+
.component('v-github-icon', VGithubIcon)
|
48 |
+
// .use(createMetaManager())
|
49 |
+
|
50 |
+
// await router.isReady()
|
51 |
+
app.mount('#app')
|
frontend/src/plugins/router.js
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createRouter, createWebHistory } from 'vue-router'
|
2 |
+
|
3 |
+
const routes = [
|
4 |
+
{
|
5 |
+
path: '/analyzer',
|
6 |
+
name: 'Analyzer',
|
7 |
+
component: () => import('@/views/Analyzer.vue'),
|
8 |
+
},
|
9 |
+
{
|
10 |
+
path: '/',
|
11 |
+
name: 'Home',
|
12 |
+
component: () => import('@/views/Home.vue'),
|
13 |
+
},
|
14 |
+
]
|
15 |
+
|
16 |
+
const router = createRouter({
|
17 |
+
history: createWebHistory(),
|
18 |
+
routes,
|
19 |
+
})
|
20 |
+
|
21 |
+
export { router }
|
frontend/src/style.css
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
:root {
|
2 |
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
3 |
+
line-height: 1.5;
|
4 |
+
font-weight: 400;
|
5 |
+
|
6 |
+
color-scheme: light dark;
|
7 |
+
color: rgba(255, 255, 255, 0.87);
|
8 |
+
background-color: #242424;
|
9 |
+
|
10 |
+
font-synthesis: none;
|
11 |
+
text-rendering: optimizeLegibility;
|
12 |
+
-webkit-font-smoothing: antialiased;
|
13 |
+
-moz-osx-font-smoothing: grayscale;
|
14 |
+
|
15 |
+
--primary-color: #3498db;
|
16 |
+
--background-light: #c6dbfa;
|
17 |
+
--background-dark: #3c3d3d;
|
18 |
+
--accent-color: #b9a329;
|
19 |
+
--text-color-dark: #333333;
|
20 |
+
--text-color-light: #e0e0e0;
|
21 |
+
}
|
22 |
+
|
23 |
+
a {
|
24 |
+
font-weight: 500;
|
25 |
+
color: #646cff;
|
26 |
+
text-decoration: inherit;
|
27 |
+
}
|
28 |
+
a:hover {
|
29 |
+
color: #535bf2;
|
30 |
+
}
|
31 |
+
|
32 |
+
body {
|
33 |
+
margin: 0px;
|
34 |
+
display: flex;
|
35 |
+
place-items: top center;
|
36 |
+
min-width: 320px;
|
37 |
+
min-height: 100vh;
|
38 |
+
/* background-color: #ff0000; */
|
39 |
+
background-color: var(--background-light);
|
40 |
+
|
41 |
+
overflow: auto;
|
42 |
+
|
43 |
+
}
|
44 |
+
|
45 |
+
body::-webkit-scrollbar {
|
46 |
+
width: 0em;
|
47 |
+
}
|
48 |
+
|
49 |
+
body::-webkit-scrollbar-thumb {
|
50 |
+
background-color: #888; /* Color of the thumb */
|
51 |
+
border-radius: 0.25em; /* Roundness of the thumb */
|
52 |
+
display: none;
|
53 |
+
}
|
54 |
+
|
55 |
+
body::-webkit-scrollbar-track {
|
56 |
+
background-color: #f0f0f0; /* Color of the track */
|
57 |
+
display: none;
|
58 |
+
}
|
59 |
+
|
60 |
+
h1 {
|
61 |
+
font-size: 3.2em;
|
62 |
+
line-height: 1.1;
|
63 |
+
}
|
64 |
+
|
65 |
+
button {
|
66 |
+
border-radius: 8px;
|
67 |
+
border: 1px solid transparent;
|
68 |
+
padding: 0.6em 1.2em;
|
69 |
+
font-size: 1em;
|
70 |
+
font-weight: 500;
|
71 |
+
font-family: inherit;
|
72 |
+
background-color: #1a1a1a;
|
73 |
+
cursor: pointer;
|
74 |
+
transition: border-color 0.25s;
|
75 |
+
}
|
76 |
+
button:hover {
|
77 |
+
border-color: #646cff;
|
78 |
+
}
|
79 |
+
button:focus,
|
80 |
+
button:focus-visible {
|
81 |
+
outline: 4px auto -webkit-focus-ring-color;
|
82 |
+
}
|
83 |
+
|
84 |
+
.card {
|
85 |
+
padding: 2em;
|
86 |
+
}
|
87 |
+
|
88 |
+
#app {
|
89 |
+
max-width: 1280px;
|
90 |
+
margin: 0 auto;
|
91 |
+
padding: 2rem;
|
92 |
+
text-align: center;
|
93 |
+
background-color: var(--background-dark);
|
94 |
+
margin-top: 0px;
|
95 |
+
border-radius: 8px;
|
96 |
+
/* give some 3d shade */
|
97 |
+
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
|
98 |
+
}
|
99 |
+
|
100 |
+
@media (prefers-color-scheme: light) {
|
101 |
+
:root {
|
102 |
+
color: #213547;
|
103 |
+
background-color: #ffffff;
|
104 |
+
}
|
105 |
+
a:hover {
|
106 |
+
color: #747bff;
|
107 |
+
}
|
108 |
+
button {
|
109 |
+
background-color: #f9f9f9;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
.editorBox {
|
115 |
+
min-height: 100px;
|
116 |
+
min-width: 200px;
|
117 |
+
width: 500px;
|
118 |
+
height: 145px;
|
119 |
+
max-width:800px;
|
120 |
+
overflow: auto;
|
121 |
+
background-color: rgb(40, 41, 46);
|
122 |
+
color: rgb(187, 188, 196);
|
123 |
+
border-radius: 8px;
|
124 |
+
}
|
125 |
+
.editorBox::-webkit-scrollbar {
|
126 |
+
width: 0.5em;
|
127 |
+
}
|
128 |
+
|
129 |
+
.editorBox::-webkit-scrollbar-thumb {
|
130 |
+
background-color: #888; /* Color of the thumb */
|
131 |
+
border-radius: 0.25em; /* Roundness of the thumb */
|
132 |
+
}
|
133 |
+
|
134 |
+
.editorBox::-webkit-scrollbar-track {
|
135 |
+
background-color: #f0f0f0; /* Color of the track */
|
136 |
+
}
|
137 |
+
|
138 |
+
.parsing-error {
|
139 |
+
color: red;
|
140 |
+
margin-top: 10px;
|
141 |
+
text-align: left; /* Set text alignment to left */
|
142 |
+
}
|
143 |
+
|
144 |
+
.scoreContainer {
|
145 |
+
border: 0px solid rgb(212, 22, 22);
|
146 |
+
overflow-x: auto;
|
147 |
+
}
|
148 |
+
.scoreContainer::-webkit-scrollbar {
|
149 |
+
height: 0.5em;
|
150 |
+
}
|
151 |
+
.scoreContainer::-webkit-scrollbar-thumb {
|
152 |
+
background-color: #888; /* Color of the thumb */
|
153 |
+
border-radius: 0.25em; /* Roundness of the thumb */
|
154 |
+
}
|
155 |
+
.scoreContainer::-webkit-scrollbar-track {
|
156 |
+
background-color: #f0f0f0; /* Color of the track */
|
157 |
+
}
|
frontend/src/views/Analyzer.vue
ADDED
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script setup>
|
2 |
+
import { client } from '@gradio/client'
|
3 |
+
import { onMounted, ref } from 'vue'
|
4 |
+
import VextabWidget from '@/components/VextabWidget.vue'
|
5 |
+
import MusicXmlWidget from '@/components/MusicXmlWidget.vue'
|
6 |
+
import '@/style.css'
|
7 |
+
|
8 |
+
let app = null
|
9 |
+
const response = ref('')
|
10 |
+
const currentTab = ref(0)
|
11 |
+
const currentScoreCode = ref('')
|
12 |
+
const tabs = [
|
13 |
+
{ name: 'VexTab', component: VextabWidget, id: 'first' },
|
14 |
+
{ name: 'VexTab2', component: VextabWidget, id: 'second' },
|
15 |
+
{ name: 'MusicXml', component: MusicXmlWidget, id: 'second' },
|
16 |
+
]
|
17 |
+
const tabText_component1 = `
|
18 |
+
tabstave notation=true key=A time=4/4
|
19 |
+
|
20 |
+
notes :q =|: (5/2.5/3.7/4) :8 7-5h6/3 ^3^ 5h6-7/5 ^3^ :q 7V/4 |
|
21 |
+
notes :8 t12p7/4 s5s3/4 :8 3s:16:5-7/5 :q p5/4
|
22 |
+
text :w, |#segno, ,|, :hd, , #tr
|
23 |
+
`
|
24 |
+
const tabText_component2 = `
|
25 |
+
tabstave notation=true key=A time=4/4
|
26 |
+
|
27 |
+
notes :q =|: (5/2.5/3.7/4) :8 7-5h6/3 ^3^ 5h6-7/5 ^3^ :q 7V/4 |
|
28 |
+
`
|
29 |
+
|
30 |
+
async function connectToServer() {
|
31 |
+
try {
|
32 |
+
app = await client('xribene/guitar_diff')
|
33 |
+
}
|
34 |
+
catch (error) {
|
35 |
+
console.error('Error fetching data:', error)
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
onMounted(async () => {
|
40 |
+
// Call the async function when the component is mounted
|
41 |
+
await connectToServer()
|
42 |
+
})
|
43 |
+
|
44 |
+
async function processScore() {
|
45 |
+
try {
|
46 |
+
const result = await app.predict('/process', [currentScoreCode.value])
|
47 |
+
response.value = result.data
|
48 |
+
console.log(result.data)
|
49 |
+
}
|
50 |
+
catch (error) {
|
51 |
+
console.error('Error processing the score:', error)
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
function updateScoreCode(scoreCode) {
|
56 |
+
currentScoreCode.value = scoreCode
|
57 |
+
// console.log("updateScoreCode")
|
58 |
+
// console.log(currentScoreCode.value);
|
59 |
+
}
|
60 |
+
</script>
|
61 |
+
|
62 |
+
<template>
|
63 |
+
<div class="guitar-score-analyzer">
|
64 |
+
<h1 class="title">
|
65 |
+
Guitar Score Analyzer
|
66 |
+
</h1>
|
67 |
+
<p class="description">
|
68 |
+
You can load a guitar score either using Vextab or MusicXml
|
69 |
+
</p>
|
70 |
+
<br>
|
71 |
+
|
72 |
+
<!-- Tab Buttons -->
|
73 |
+
<div class="debug-background-color tab-buttons">
|
74 |
+
<button
|
75 |
+
v-for="(tab, index) in tabs"
|
76 |
+
:key="index"
|
77 |
+
class="tab-button" :class="[{ active: currentTab === index }]"
|
78 |
+
@click="currentTab = index"
|
79 |
+
>
|
80 |
+
{{ tab.name }}
|
81 |
+
</button>
|
82 |
+
</div>
|
83 |
+
<br>
|
84 |
+
<br>
|
85 |
+
<br>
|
86 |
+
|
87 |
+
<!-- <div>
|
88 |
+
<TweakComponent />
|
89 |
+
</div> -->
|
90 |
+
<!-- Vextab Widget -->
|
91 |
+
<div v-show="currentTab === 0" class="tab" :class="{ active: currentTab === 0 }">
|
92 |
+
<VextabWidget
|
93 |
+
:id="tabs[currentTab].id"
|
94 |
+
class="tab-vexTab"
|
95 |
+
:tab-text="tabText_component1"
|
96 |
+
:is-active="currentTab === 0"
|
97 |
+
@update-score-code="updateScoreCode"
|
98 |
+
/>
|
99 |
+
</div>
|
100 |
+
|
101 |
+
<div v-show="currentTab === 1" class="tab" :class="{ active: currentTab === 1 }">
|
102 |
+
<VextabWidget
|
103 |
+
:id="tabs[currentTab].id"
|
104 |
+
class="tab-vexTab"
|
105 |
+
:tab-text="tabText_component2"
|
106 |
+
:is-active="currentTab === 1"
|
107 |
+
@update-score-code="updateScoreCode"
|
108 |
+
/>
|
109 |
+
</div>
|
110 |
+
|
111 |
+
<!-- MusicXml Widget -->
|
112 |
+
<div v-show="currentTab === 2" class="tab" :class="{ active: currentTab === 2 }">
|
113 |
+
<MusicXmlWidget
|
114 |
+
:id="tabs[currentTab].id"
|
115 |
+
class="tab-musicXml"
|
116 |
+
:is-active="currentTab === 2"
|
117 |
+
@update-score-code="updateScoreCode"
|
118 |
+
/>
|
119 |
+
</div>
|
120 |
+
|
121 |
+
<!-- Report Container -->
|
122 |
+
<div class="debug-background-color report-container">
|
123 |
+
<button class="analyze-button" @click="processScore">
|
124 |
+
Analyze
|
125 |
+
</button>
|
126 |
+
<p class="response">
|
127 |
+
{{ response }}
|
128 |
+
</p>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
</template>
|
132 |
+
|
133 |
+
<style scoped>
|
134 |
+
.guitar-score-analyzer {
|
135 |
+
max-width: 1280px; /* Adjust the max width as needed */
|
136 |
+
margin: auto;
|
137 |
+
background-color: rgb(238, 235, 212);
|
138 |
+
}
|
139 |
+
|
140 |
+
.title {
|
141 |
+
font-size: 2em;
|
142 |
+
margin-bottom: 10px;
|
143 |
+
/* background-color: aqua; */
|
144 |
+
}
|
145 |
+
|
146 |
+
.description {
|
147 |
+
font-size: 1.2em;
|
148 |
+
margin-bottom: 20px;
|
149 |
+
/* background-color: aquamarine; */
|
150 |
+
}
|
151 |
+
|
152 |
+
.tab-buttons {
|
153 |
+
display: block;
|
154 |
+
/* background-color: #4caf50; */
|
155 |
+
}
|
156 |
+
|
157 |
+
.tab-button {
|
158 |
+
background-color: rgb(248, 240, 201);
|
159 |
+
padding: 10px;
|
160 |
+
margin-right: 5px;
|
161 |
+
cursor: pointer;
|
162 |
+
}
|
163 |
+
|
164 |
+
.tab-button.active {
|
165 |
+
background-color: var(--accent-color);
|
166 |
+
}
|
167 |
+
|
168 |
+
.tab {
|
169 |
+
display: none;
|
170 |
+
}
|
171 |
+
|
172 |
+
.tab.active {
|
173 |
+
display: flex;
|
174 |
+
/* background-color: #4caf50; */
|
175 |
+
width: 800px;
|
176 |
+
max-width: 1280px;
|
177 |
+
min-width:200px;
|
178 |
+
min-height:300px;
|
179 |
+
|
180 |
+
}
|
181 |
+
|
182 |
+
.analyze-button {
|
183 |
+
padding: 10px;
|
184 |
+
background-color: #4caf50;
|
185 |
+
color: #fff;
|
186 |
+
cursor: pointer;
|
187 |
+
}
|
188 |
+
|
189 |
+
.report-container {
|
190 |
+
margin-top: 20px;
|
191 |
+
}
|
192 |
+
|
193 |
+
/* Debug Styles - Remove when done */
|
194 |
+
/* .debug-background-color {
|
195 |
+
background-color: #f0f0f0;
|
196 |
+
} */
|
197 |
+
</style>
|
frontend/src/views/Home.vue
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div class="home-container">
|
3 |
+
<!-- <a href="https://vuejs.org/" target="_blank"> -->
|
4 |
+
<img src="/cedar_guitar_800.png" class="logo" alt="guitar">
|
5 |
+
<!-- </a> -->
|
6 |
+
<h1>Home</h1>
|
7 |
+
</div>
|
8 |
+
</template>
|
9 |
+
|
10 |
+
<style scoped>
|
11 |
+
.home-container {
|
12 |
+
display: flex;
|
13 |
+
flex-direction: column;
|
14 |
+
align-items: center;
|
15 |
+
width: 800px;
|
16 |
+
max-width: 1280px; /* Adjust the max width as needed */
|
17 |
+
margin: auto;
|
18 |
+
background-color: bisque;
|
19 |
+
}
|
20 |
+
|
21 |
+
.logo {
|
22 |
+
height: 12em;
|
23 |
+
padding: 1.5em;
|
24 |
+
will-change: filter;
|
25 |
+
transition: filter 300ms;
|
26 |
+
}
|
27 |
+
.logo:hover {
|
28 |
+
filter: drop-shadow(0 0 2em #646cffaa);
|
29 |
+
}
|
30 |
+
.logo.vue:hover {
|
31 |
+
filter: drop-shadow(0 0 2em #b8a642aa);
|
32 |
+
}
|
33 |
+
</style>
|
frontend/uno.config.js
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {
|
2 |
+
defineConfig,
|
3 |
+
// presetIcons,
|
4 |
+
presetUno,
|
5 |
+
presetWebFonts,
|
6 |
+
transformerDirectives,
|
7 |
+
transformerVariantGroup,
|
8 |
+
} from 'unocss'
|
9 |
+
|
10 |
+
import presetIcons from '@unocss/preset-icons/browser'
|
11 |
+
|
12 |
+
export default defineConfig({
|
13 |
+
presets: [
|
14 |
+
presetUno(),
|
15 |
+
presetIcons({
|
16 |
+
scale: 1.5,
|
17 |
+
warn: true,
|
18 |
+
unit: 'em',
|
19 |
+
extraProperties: {
|
20 |
+
'display': 'inline-block',
|
21 |
+
'vertical-align': 'middle',
|
22 |
+
// ...
|
23 |
+
},
|
24 |
+
collections: {
|
25 |
+
// carbon: () => import('@iconify/json/carbon.json').then(i => i.default),
|
26 |
+
// mdi: () => import('@iconify/json/mid.json').then(i => i.default),
|
27 |
+
// logos: () => import('@iconify/json/logos.json').then(i => i.default),
|
28 |
+
// twemoji: () => import('@iconify/json/twemoji.json').then(i => i.default),
|
29 |
+
mdi: () => import('@iconify/json/json/mdi.json').then(i => i.default),
|
30 |
+
logos: () => import('@iconify/json/json/logos.json').then(i => i.default),
|
31 |
+
twemoji: () => import('@iconify/json/json/twemoji.json').then(i => i.default),
|
32 |
+
vscode: () => import('@iconify/json/json/vscode-icons.json').then(i => i.default),
|
33 |
+
},
|
34 |
+
}),
|
35 |
+
presetWebFonts({
|
36 |
+
provider: 'bunny',
|
37 |
+
fonts: {
|
38 |
+
sans: 'Inter',
|
39 |
+
},
|
40 |
+
}),
|
41 |
+
],
|
42 |
+
transformers: [
|
43 |
+
transformerDirectives(),
|
44 |
+
transformerVariantGroup(),
|
45 |
+
],
|
46 |
+
})
|
frontend/vite.config.js
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import path from 'node:path'
|
2 |
+
import UnoCSS from 'unocss/vite'
|
3 |
+
import { defineConfig } from 'vite'
|
4 |
+
import vue from '@vitejs/plugin-vue'
|
5 |
+
|
6 |
+
// https://vitejs.dev/config/
|
7 |
+
export default defineConfig({
|
8 |
+
plugins: [
|
9 |
+
vue(),
|
10 |
+
UnoCSS(),
|
11 |
+
],
|
12 |
+
resolve: {
|
13 |
+
alias: {
|
14 |
+
'@': path.resolve(__dirname, './src'),
|
15 |
+
},
|
16 |
+
},
|
17 |
+
// build:{
|
18 |
+
// target: "esnext" // or "es2019",
|
19 |
+
// }
|
20 |
+
|
21 |
+
})
|
pyproject.toml
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[tool.ruff]
|
2 |
+
# Exclude a variety of commonly ignored directories.
|
3 |
+
exclude = [
|
4 |
+
".bzr",
|
5 |
+
".direnv",
|
6 |
+
".eggs",
|
7 |
+
".git",
|
8 |
+
".git-rewrite",
|
9 |
+
".hg",
|
10 |
+
".ipynb_checkpoints",
|
11 |
+
".mypy_cache",
|
12 |
+
".nox",
|
13 |
+
".pants.d",
|
14 |
+
".pyenv",
|
15 |
+
".pytest_cache",
|
16 |
+
".pytype",
|
17 |
+
".ruff_cache",
|
18 |
+
".svn",
|
19 |
+
".tox",
|
20 |
+
".venv",
|
21 |
+
".vscode",
|
22 |
+
"__pypackages__",
|
23 |
+
"_build",
|
24 |
+
"buck-out",
|
25 |
+
"build",
|
26 |
+
"dist",
|
27 |
+
"node_modules",
|
28 |
+
"site-packages",
|
29 |
+
"venv",
|
30 |
+
"frontend"
|
31 |
+
]
|
32 |
+
|
33 |
+
# Same as Black.
|
34 |
+
line-length = 100
|
35 |
+
indent-width = 4
|
36 |
+
|
37 |
+
# Assume Python 3.9
|
38 |
+
target-version = "py39"
|
39 |
+
|
40 |
+
[tool.ruff.lint]
|
41 |
+
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
42 |
+
# select = ["E4", "E7", "E9", "F", "W", "PLR"]
|
43 |
+
select = ["ALL"]
|
44 |
+
ignore = ["ERA", "T201"]
|
45 |
+
|
46 |
+
# Allow fix for all enabled rules (when `--fix`) is provided.
|
47 |
+
fixable = ["ALL"]
|
48 |
+
unfixable = []
|
49 |
+
|
50 |
+
# Allow unused variables when underscore-prefixed.
|
51 |
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
52 |
+
|
53 |
+
[tool.ruff.lint.pylint]
|
54 |
+
max-args = 5
|
55 |
+
|
56 |
+
[tool.ruff.lint.pycodestyle]
|
57 |
+
max-doc-length = 100
|
58 |
+
|
59 |
+
[tool.ruff.format]
|
60 |
+
# Like Black, use double quotes for strings.
|
61 |
+
quote-style = "double"
|
62 |
+
|
63 |
+
# Like Black, indent with spaces, rather than tabs.
|
64 |
+
indent-style = "space"
|
65 |
+
|
66 |
+
# Like Black, respect magic trailing commas.
|
67 |
+
skip-magic-trailing-comma = false
|
68 |
+
|
69 |
+
# Like Black, automatically detect the appropriate line ending.
|
70 |
+
line-ending = "auto"
|