@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.
@@ -0,0 +1,4 @@
1
+ # Package Managers
2
+ package-lock.json
3
+ pnpm-lock.yaml
4
+ yarn.lock
package/.prettierrc ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "useTabs": true,
3
+ "singleQuote": true,
4
+ "trailingComma": "none",
5
+ "printWidth": 100,
6
+ "plugins": ["prettier-plugin-svelte"],
7
+ "overrides": [
8
+ {
9
+ "files": "*.svelte",
10
+ "options": {
11
+ "parser": "svelte"
12
+ }
13
+ }
14
+ ]
15
+ }
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.
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ // Created scripts/package-pre.js
2
+
3
+ import { MakeLibIndex } from '../../shared/scripts/indexIfy.js';
4
+ new MakeLibIndex().makeIndexFile();
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>
@@ -0,0 +1,7 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
3
+ describe('sum test', () => {
4
+ it('adds 1 + 2 to equal 3', () => {
5
+ expect(1 + 2).toBe(3);
6
+ });
7
+ });
@@ -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
+ }
@@ -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
+ };
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ import App from "../lib/components/App.svelte";
3
+
4
+ </script>
5
+
6
+
7
+ <App />
Binary file
@@ -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
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import { sveltekit } from '@sveltejs/kit/vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()],
6
+
7
+ test: {
8
+ include: ['src/**/*.{test,spec}.{js,ts}']
9
+ }
10
+ });