@medyll/idae-cadenzia 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +4 -0
- package/.prettierrc +15 -0
- package/CHANGELOG.md +7 -0
- package/README.md +38 -0
- package/eslint.config.js +33 -0
- package/package.json +36 -0
- package/scripts/package-pre.js +4 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +12 -0
- package/src/demo.spec.ts +7 -0
- package/src/lib/components/App.svelte +47 -0
- package/src/lib/components/CadencePanel.svelte +25 -0
- package/src/lib/components/ChordTable.svelte +145 -0
- package/src/lib/components/ChordVisualization.svelte +81 -0
- package/src/lib/functions/functions.svelte.ts +66 -0
- package/src/lib/index.ts +7 -0
- package/src/lib/types/types.ts +25 -0
- package/src/routes/+page.svelte +7 -0
- package/static/favicon.png +0 -0
- package/svelte.config.js +18 -0
- package/tsconfig.json +19 -0
- package/vite.config.ts +10 -0
package/.prettierignore
ADDED
package/.prettierrc
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @medyll/idae-cadenzia
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- - feat(ajouter): le composant App et les composants associés pour la visualisation des accords ([e7c9517](https://github.com/medyll/idae/commit/e7c95178e328e56f514678bed4c96015e7ef7529)) - 2024-11-16 by @medyll
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# sv
|
|
2
|
+
|
|
3
|
+
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
|
4
|
+
|
|
5
|
+
## Creating a project
|
|
6
|
+
|
|
7
|
+
If you're seeing this, you've probably already done this step. Congrats!
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# create a new project in the current directory
|
|
11
|
+
npx sv create
|
|
12
|
+
|
|
13
|
+
# create a new project in my-app
|
|
14
|
+
npx sv create my-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Developing
|
|
18
|
+
|
|
19
|
+
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm run dev
|
|
23
|
+
|
|
24
|
+
# or start the server and open the app in a new browser tab
|
|
25
|
+
npm run dev -- --open
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Building
|
|
29
|
+
|
|
30
|
+
To create a production version of your app:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run build
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
You can preview the production build with `npm run preview`.
|
|
37
|
+
|
|
38
|
+
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import prettier from 'eslint-config-prettier';
|
|
2
|
+
import js from '@eslint/js';
|
|
3
|
+
import svelte from 'eslint-plugin-svelte';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
import ts from 'typescript-eslint';
|
|
6
|
+
|
|
7
|
+
export default ts.config(
|
|
8
|
+
js.configs.recommended,
|
|
9
|
+
...ts.configs.recommended,
|
|
10
|
+
...svelte.configs['flat/recommended'],
|
|
11
|
+
prettier,
|
|
12
|
+
...svelte.configs['flat/prettier'],
|
|
13
|
+
{
|
|
14
|
+
languageOptions: {
|
|
15
|
+
globals: {
|
|
16
|
+
...globals.browser,
|
|
17
|
+
...globals.node
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
files: ['**/*.svelte'],
|
|
23
|
+
|
|
24
|
+
languageOptions: {
|
|
25
|
+
parserOptions: {
|
|
26
|
+
parser: ts.parser
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
ignores: ['build/', '.svelte-kit/', 'dist/']
|
|
32
|
+
}
|
|
33
|
+
);
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@medyll/idae-cadenzia",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite dev",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
10
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
11
|
+
"format": "prettier --write .",
|
|
12
|
+
"lint": "prettier --check . && eslint .",
|
|
13
|
+
"test:unit": "vitest",
|
|
14
|
+
"test": "npm run test:unit -- --run",
|
|
15
|
+
"package:pre": "node scripts/package-pre.js"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@sveltejs/adapter-auto": "^3.0.0",
|
|
19
|
+
"@sveltejs/kit": "^2.0.0",
|
|
20
|
+
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
|
21
|
+
"@types/eslint": "^9.6.0",
|
|
22
|
+
"eslint": "^9.7.0",
|
|
23
|
+
"eslint-config-prettier": "^9.1.0",
|
|
24
|
+
"eslint-plugin-svelte": "^2.36.0",
|
|
25
|
+
"globals": "^15.0.0",
|
|
26
|
+
"prettier": "^3.3.2",
|
|
27
|
+
"prettier-plugin-svelte": "^3.2.6",
|
|
28
|
+
"svelte": "^5.0.0",
|
|
29
|
+
"svelte-check": "^4.0.0",
|
|
30
|
+
"typescript": "^5.0.0",
|
|
31
|
+
"typescript-eslint": "^8.0.0",
|
|
32
|
+
"vite": "^5.0.3",
|
|
33
|
+
"vitest": "^2.0.4"
|
|
34
|
+
},
|
|
35
|
+
"scope": "@medyll"
|
|
36
|
+
}
|
package/src/app.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// See https://svelte.dev/docs/kit/types#app.d.ts
|
|
2
|
+
// for information about these interfaces
|
|
3
|
+
declare global {
|
|
4
|
+
namespace App {
|
|
5
|
+
// interface Error {}
|
|
6
|
+
// interface Locals {}
|
|
7
|
+
// interface PageData {}
|
|
8
|
+
// interface PageState {}
|
|
9
|
+
// interface Platform {}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export {};
|
package/src/app.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
%sveltekit.head%
|
|
8
|
+
</head>
|
|
9
|
+
<body data-sveltekit-preload-data="hover">
|
|
10
|
+
<div style="display: contents">%sveltekit.body%</div>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
package/src/demo.spec.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ChordTable from './ChordTable.svelte';
|
|
3
|
+
import CadencePanel from './CadencePanel.svelte';
|
|
4
|
+
import ChordVisualization from './ChordVisualization.svelte';
|
|
5
|
+
import { chords, suggestedCadences } from '../functions/functions.svelte.js';
|
|
6
|
+
|
|
7
|
+
function handleNewFile() {
|
|
8
|
+
console.log('New file');
|
|
9
|
+
chords.length = 0;
|
|
10
|
+
suggestedCadences.length = 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function handleOpenFile() {
|
|
14
|
+
console.log('Open file');
|
|
15
|
+
// Implement logic to open a file here
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function handleSaveFile() {
|
|
19
|
+
console.log('Save file');
|
|
20
|
+
// Implement logic to save a file here
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<main>
|
|
25
|
+
<h1>Music Composer</h1>
|
|
26
|
+
<div>
|
|
27
|
+
<button onclick={handleNewFile}>New</button>
|
|
28
|
+
<button onclick={handleOpenFile}>Open</button>
|
|
29
|
+
<button onclick={handleSaveFile}>Save</button>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<ChordTable />
|
|
33
|
+
<CadencePanel />
|
|
34
|
+
<ChordVisualization />
|
|
35
|
+
</main>
|
|
36
|
+
|
|
37
|
+
<style>
|
|
38
|
+
main {
|
|
39
|
+
font-family: Arial, sans-serif;
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
margin: 0 auto;
|
|
42
|
+
padding: 20px;
|
|
43
|
+
}
|
|
44
|
+
button {
|
|
45
|
+
margin-right: 10px;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- components/CadencePanel.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { suggestedCadences } from '../functions/functions.svelte.js';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div class="cadence-panel">
|
|
7
|
+
<h3>Suggested Cadences:</h3>
|
|
8
|
+
{#if suggestedCadences.length === 0}
|
|
9
|
+
<p>No cadences available at the moment.</p>
|
|
10
|
+
{:else}
|
|
11
|
+
<ul>
|
|
12
|
+
{#each suggestedCadences as cadence}
|
|
13
|
+
<li>{cadence.name}: {cadence.chords.join(' - ')}</li>
|
|
14
|
+
{/each}
|
|
15
|
+
</ul>
|
|
16
|
+
{/if}
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
.cadence-panel {
|
|
21
|
+
background-color: #f0f0f0;
|
|
22
|
+
padding: 10px;
|
|
23
|
+
margin-top: 20px;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<!-- components/ChordTable.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import {
|
|
4
|
+
chordEntries,
|
|
5
|
+
updateCadences,
|
|
6
|
+
qualities,
|
|
7
|
+
rootNotes,
|
|
8
|
+
modifiers,
|
|
9
|
+
toggleModifier
|
|
10
|
+
} from '../functions/functions.svelte.js';
|
|
11
|
+
|
|
12
|
+
function addChordEntry() {
|
|
13
|
+
chordEntries.push({
|
|
14
|
+
chord: { root: 'C', quality: qualities.mode[0], modifier: undefined, duration: '1' },
|
|
15
|
+
timeSignature: chordEntries.length === 0 ? { numerator: 4, denominator: 4 } : undefined
|
|
16
|
+
});
|
|
17
|
+
updateCadences();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function removeChordEntry(index: number) {
|
|
21
|
+
chordEntries.splice(index, 1);
|
|
22
|
+
updateCadences();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function handleChordChange() {
|
|
26
|
+
updateCadences();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function toggleTimeSignature(index: number) {
|
|
30
|
+
if (chordEntries[index].timeSignature) {
|
|
31
|
+
chordEntries[index].timeSignature = undefined;
|
|
32
|
+
} else {
|
|
33
|
+
chordEntries[index].timeSignature = { numerator: 4, denominator: 4 };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<table>
|
|
39
|
+
<thead>
|
|
40
|
+
<tr>
|
|
41
|
+
<th>Measure</th>
|
|
42
|
+
<th>Time Signature</th>
|
|
43
|
+
<th>Root</th>
|
|
44
|
+
<th>Quality</th>
|
|
45
|
+
<th>Modifier</th>
|
|
46
|
+
<th>Duration</th>
|
|
47
|
+
<th>Action</th>
|
|
48
|
+
</tr>
|
|
49
|
+
</thead>
|
|
50
|
+
<tbody>
|
|
51
|
+
{#each chordEntries as entry, i}
|
|
52
|
+
<tr>
|
|
53
|
+
<td>{i + 1}</td>
|
|
54
|
+
<td>
|
|
55
|
+
{#if entry.timeSignature}
|
|
56
|
+
<input type="number" bind:value={entry.timeSignature.numerator} min="1" max="32" />
|
|
57
|
+
/
|
|
58
|
+
<input type="number" bind:value={entry.timeSignature.denominator} min="1" max="32" />
|
|
59
|
+
{:else}
|
|
60
|
+
<button onclick={() => toggleTimeSignature(i)}>Add Time Signature</button>
|
|
61
|
+
{/if}
|
|
62
|
+
</td>
|
|
63
|
+
<td>
|
|
64
|
+
<select bind:value={entry.chord.root} onchange={handleChordChange}>
|
|
65
|
+
{#each rootNotes as note}
|
|
66
|
+
<option value={note}>{note}</option>
|
|
67
|
+
{/each}
|
|
68
|
+
</select>
|
|
69
|
+
</td>
|
|
70
|
+
<td>
|
|
71
|
+
{#each Object.entries(qualities) as [group, qualityOptions]}
|
|
72
|
+
<div>
|
|
73
|
+
{#each qualityOptions as quality}
|
|
74
|
+
<label>
|
|
75
|
+
<input
|
|
76
|
+
type="radio"
|
|
77
|
+
name={`quality-${group}-${i}`}
|
|
78
|
+
value={quality}
|
|
79
|
+
checked={entry.chord[group] === quality}
|
|
80
|
+
onchange={() => {
|
|
81
|
+
entry.chord[group] = quality;
|
|
82
|
+
entry.chord.quality = quality;
|
|
83
|
+
handleChordChange();
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
{quality}
|
|
87
|
+
</label>
|
|
88
|
+
{/each}
|
|
89
|
+
</div>
|
|
90
|
+
<hr />
|
|
91
|
+
{/each}
|
|
92
|
+
</td>
|
|
93
|
+
<td>
|
|
94
|
+
{#each modifiers as modifier}
|
|
95
|
+
<label>
|
|
96
|
+
<input
|
|
97
|
+
type="radio"
|
|
98
|
+
name={`modifier-${i}`}
|
|
99
|
+
value={modifier}
|
|
100
|
+
checked={entry.chord.modifier === modifier}
|
|
101
|
+
onchange={() => toggleModifier(i, modifier)}
|
|
102
|
+
/>
|
|
103
|
+
{modifier}
|
|
104
|
+
</label>
|
|
105
|
+
{/each}
|
|
106
|
+
</td>
|
|
107
|
+
<td>
|
|
108
|
+
<input
|
|
109
|
+
type="text"
|
|
110
|
+
bind:value={entry.chord.duration}
|
|
111
|
+
onchange={handleChordChange}
|
|
112
|
+
placeholder="e.g., 1, 1/2, 3/4"
|
|
113
|
+
/>
|
|
114
|
+
</td>
|
|
115
|
+
<td>
|
|
116
|
+
<button onclick={() => removeChordEntry(i)}>Remove</button>
|
|
117
|
+
</td>
|
|
118
|
+
</tr>
|
|
119
|
+
{/each}
|
|
120
|
+
</tbody>
|
|
121
|
+
</table>
|
|
122
|
+
|
|
123
|
+
<button onclick={addChordEntry}>Add Chord</button>
|
|
124
|
+
|
|
125
|
+
<style>
|
|
126
|
+
table {
|
|
127
|
+
width: 100%;
|
|
128
|
+
border-collapse: collapse;
|
|
129
|
+
margin-bottom: 1em;
|
|
130
|
+
}
|
|
131
|
+
th,
|
|
132
|
+
td {
|
|
133
|
+
border: 1px solid #ddd;
|
|
134
|
+
padding: 8px;
|
|
135
|
+
text-align: left;
|
|
136
|
+
}
|
|
137
|
+
th {
|
|
138
|
+
background-color: #f2f2f2;
|
|
139
|
+
}
|
|
140
|
+
select,
|
|
141
|
+
input[type='text'],
|
|
142
|
+
input[type='number'] {
|
|
143
|
+
width: 100%;
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!-- components/ChordVisualization.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { chordEntries } from '$lib/functions/functions.svelte';
|
|
4
|
+
import type { ChordEntry } from '$lib/types/types';
|
|
5
|
+
|
|
6
|
+
function getChordName(entry: ChordEntry) {
|
|
7
|
+
const { chord } = entry;
|
|
8
|
+
let name = chord.root;
|
|
9
|
+
|
|
10
|
+
if (chord.modifier) {
|
|
11
|
+
name += chord.modifier;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
name += chord.mode ?? '';
|
|
15
|
+
name += chord.augDim ?? '';
|
|
16
|
+
name += chord.sus ?? '';
|
|
17
|
+
name += chord.sept ?? '';
|
|
18
|
+
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getDurationValue(duration: string): number {
|
|
23
|
+
if (duration.includes('/')) {
|
|
24
|
+
const [numerator, denominator] = duration.split('/').map(Number);
|
|
25
|
+
return numerator / denominator;
|
|
26
|
+
}
|
|
27
|
+
return Number(duration);
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class="visualization">
|
|
32
|
+
<h3>Chord Visualization</h3>
|
|
33
|
+
{#if chordEntries.length === 0}
|
|
34
|
+
<p>No chords to visualize.</p>
|
|
35
|
+
{:else}
|
|
36
|
+
<div class="chord-sequence">
|
|
37
|
+
{#each chordEntries as entry, i}
|
|
38
|
+
{#if entry.timeSignature}
|
|
39
|
+
<div class="signature">
|
|
40
|
+
- Signature: {entry.timeSignature.numerator}/{entry.timeSignature.denominator}
|
|
41
|
+
</div>
|
|
42
|
+
{/if}
|
|
43
|
+
<div
|
|
44
|
+
class="chord"
|
|
45
|
+
style="--baseTime:{getDurationValue(entry.chord.duration)}"
|
|
46
|
+
>
|
|
47
|
+
<span>{getChordName(entry)}</span>
|
|
48
|
+
<span>{entry.chord.duration}</span>
|
|
49
|
+
</div>
|
|
50
|
+
{/each}
|
|
51
|
+
</div>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
.visualization {
|
|
57
|
+
margin-top: 20px;
|
|
58
|
+
padding: 10px;
|
|
59
|
+
background-color: #e0e0e0;
|
|
60
|
+
}
|
|
61
|
+
.signature {
|
|
62
|
+
flex-basis: 100%;
|
|
63
|
+
width: 100%;
|
|
64
|
+
}
|
|
65
|
+
.chord-sequence {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-wrap: wrap;
|
|
68
|
+
gap: 10px; /* Space between chords */
|
|
69
|
+
}
|
|
70
|
+
.chord {
|
|
71
|
+
padding: 10px;
|
|
72
|
+
background-color: #fff;
|
|
73
|
+
border: 1px solid #ccc;
|
|
74
|
+
border-radius: 5px;
|
|
75
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
76
|
+
text-align: center;
|
|
77
|
+
width: calc(200px * var(--baseTime, 1));
|
|
78
|
+
min-width: 30px; /* Ensure a minimum width for very short durations */
|
|
79
|
+
max-width: 100%; /* Prevent oversized chords */
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// functions/functions.svelte.ts
|
|
2
|
+
import type { Chord, Cadence, ChordEntry } from '../types/types';
|
|
3
|
+
|
|
4
|
+
export const chords = $state<Chord[]>([]);
|
|
5
|
+
export const suggestedCadences = $state<Cadence[]>([]);
|
|
6
|
+
export const chordEntries = $state<ChordEntry[]>([]);
|
|
7
|
+
|
|
8
|
+
export const cadencePatterns: Cadence[] = [
|
|
9
|
+
{ name: 'Perfect', chords: ['V', 'I'] },
|
|
10
|
+
{ name: 'Plagal', chords: ['IV', 'I'] },
|
|
11
|
+
{ name: 'Deceptive', chords: ['V', 'VI'] },
|
|
12
|
+
{ name: 'Half', chords: ['I', 'V'] },
|
|
13
|
+
{ name: 'Italian', chords: ['IV', 'V', 'I'] },
|
|
14
|
+
{ name: 'German', chords: ['II', 'V', 'I'] },
|
|
15
|
+
{ name: 'Phrygian', chords: ['IV', 'V', 'III'] }
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export const rootNotes = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
|
|
19
|
+
|
|
20
|
+
export const qualities = {
|
|
21
|
+
mode: ['maj', 'min'],
|
|
22
|
+
augDim: ['aug', 'dim'],
|
|
23
|
+
sus: ['sus4', 'sus2'],
|
|
24
|
+
sept: ['7', '5']
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const modifiers = ['♯', '♭', '♮'];
|
|
28
|
+
|
|
29
|
+
export function updateCadences() {
|
|
30
|
+
console.log('Current Chords:', $state.snapshot({ chords }));
|
|
31
|
+
|
|
32
|
+
if (chordEntries.length === 0) {
|
|
33
|
+
suggestedCadences.length = 0;
|
|
34
|
+
console.log('No chords, no suggestions');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const romanNumerals = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII'];
|
|
39
|
+
const lastChord = chordEntries[chordEntries.length - 1].chord;
|
|
40
|
+
|
|
41
|
+
const rootIndex = rootNotes.indexOf(lastChord.root.toUpperCase());
|
|
42
|
+
let lastChordRoman = rootIndex !== -1 ? romanNumerals[rootIndex] : null;
|
|
43
|
+
|
|
44
|
+
if (lastChord.modifier === '♯') {
|
|
45
|
+
lastChordRoman += '#';
|
|
46
|
+
} else if (lastChord.modifier === '♭') {
|
|
47
|
+
lastChordRoman += 'b';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log('Last Chord Roman:', lastChordRoman);
|
|
51
|
+
|
|
52
|
+
const suggestions = cadencePatterns.filter((cadence) => {
|
|
53
|
+
return cadence.chords[0] === lastChordRoman;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
suggestedCadences.length = 0;
|
|
57
|
+
suggestedCadences.push(...suggestions);
|
|
58
|
+
|
|
59
|
+
console.log('Suggested Cadences:', $state.snapshot({ suggestedCadences }));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function toggleModifier(chordIndex: number, modifier: string) {
|
|
63
|
+
const chord = chordEntries[chordIndex].chord;
|
|
64
|
+
chord.modifier = chord.modifier === modifier ? undefined : modifier;
|
|
65
|
+
updateCadences();
|
|
66
|
+
}
|
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// auto exports of entry components
|
|
2
|
+
export * from '$lib/types/types.js';
|
|
3
|
+
export * from '$lib/functions/functions.svelte.js';
|
|
4
|
+
export { default as ChordVisualization } from '$lib/components/ChordVisualization.svelte';
|
|
5
|
+
export { default as ChordTable } from '$lib/components/ChordTable.svelte';
|
|
6
|
+
export { default as CadencePanel } from '$lib/components/CadencePanel.svelte';
|
|
7
|
+
export { default as App } from '$lib/components/App.svelte';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type Chord = {
|
|
2
|
+
root: string;
|
|
3
|
+
quality: string;
|
|
4
|
+
mode?: string;
|
|
5
|
+
augDim?: string;
|
|
6
|
+
sus?: string;
|
|
7
|
+
sept?: string;
|
|
8
|
+
modifier?: string;
|
|
9
|
+
duration: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type TimeSignature = {
|
|
13
|
+
numerator: number;
|
|
14
|
+
denominator: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ChordEntry = {
|
|
18
|
+
chord: Chord;
|
|
19
|
+
timeSignature?: TimeSignature;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type Cadence = {
|
|
23
|
+
name: string;
|
|
24
|
+
chords: string[];
|
|
25
|
+
};
|
|
Binary file
|
package/svelte.config.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import adapter from '@sveltejs/adapter-auto';
|
|
2
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
3
|
+
|
|
4
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
5
|
+
const config = {
|
|
6
|
+
// Consult https://svelte.dev/docs/kit/integrations
|
|
7
|
+
// for more information about preprocessors
|
|
8
|
+
preprocess: vitePreprocess(),
|
|
9
|
+
|
|
10
|
+
kit: {
|
|
11
|
+
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
|
12
|
+
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
|
13
|
+
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
|
14
|
+
adapter: adapter()
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default config;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"checkJs": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"forceConsistentCasingInFileNames": true,
|
|
8
|
+
"resolveJsonModule": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"moduleResolution": "bundler"
|
|
13
|
+
}
|
|
14
|
+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
|
15
|
+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
|
16
|
+
//
|
|
17
|
+
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
|
18
|
+
// from the referenced tsconfig.json - TypeScript does not merge them in
|
|
19
|
+
}
|