xribene commited on
Commit
df4b493
·
1 Parent(s): 7687352
Files changed (43) hide show
  1. .editorconfig +19 -0
  2. .gitignore +24 -0
  3. app.py +66 -0
  4. frontend/README.md +7 -0
  5. frontend/eslint.config.js +31 -0
  6. frontend/index.html +18 -0
  7. frontend/package-lock.json +0 -0
  8. frontend/package.json +56 -0
  9. frontend/pnpm-lock.yaml +0 -0
  10. frontend/public/_headers +1 -0
  11. frontend/public/cedar_guitar_1663.png +0 -0
  12. frontend/public/cedar_guitar_400.png +0 -0
  13. frontend/public/cedar_guitar_800.png +0 -0
  14. frontend/public/example.xml +0 -0
  15. frontend/public/g14671.png +0 -0
  16. frontend/public/g9541.png +0 -0
  17. frontend/public/guitar-diff-example.musicxml +507 -0
  18. frontend/public/guitar-diff-example.vextab.txt +6 -0
  19. frontend/public/guitarDiffLogo2.svg +0 -0
  20. frontend/public/guitarDiffLogo3.svg +0 -0
  21. frontend/public/guitar_faded_noReport.png +0 -0
  22. frontend/public/guitar_rotated.svg +0 -0
  23. frontend/public/guitar_rotated_report.svg +0 -0
  24. frontend/public/guitar_straight.svg +0 -0
  25. frontend/public/inkscape_canvas.svg +0 -0
  26. frontend/public/test.svg +0 -0
  27. frontend/public/vite.svg +1 -0
  28. frontend/src/App.vue +89 -0
  29. frontend/src/assets/vue.svg +1 -0
  30. frontend/src/components/CounterButton.vue +20 -0
  31. frontend/src/components/HelloWorld.vue +42 -0
  32. frontend/src/components/MusicXmlWidget.vue +320 -0
  33. frontend/src/components/TweakComponent.vue +26 -0
  34. frontend/src/components/TweakComponent2.vue +107 -0
  35. frontend/src/components/VextabWidget.vue +225 -0
  36. frontend/src/main.js +51 -0
  37. frontend/src/plugins/router.js +21 -0
  38. frontend/src/style.css +157 -0
  39. frontend/src/views/Analyzer.vue +197 -0
  40. frontend/src/views/Home.vue +33 -0
  41. frontend/uno.config.js +46 -0
  42. frontend/vite.config.js +21 -0
  43. 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"