SREAL commited on
Commit
fc0073f
·
verified ·
1 Parent(s): 7307ae9

I want to create a fully functional tone.js synth that uses midi input from a midi device. is polyphonic, velocity sensitive. I want it to be a saw wave oscillator with filters and envelopes, also add some post processing effects using tone.js

Browse files
Files changed (8) hide show
  1. README.md +7 -4
  2. components/footer.js +63 -0
  3. components/navbar.js +84 -0
  4. index.html +156 -19
  5. presets.html +164 -0
  6. script.js +334 -0
  7. sequencer.html +77 -0
  8. style.css +111 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Synthwave Studio
3
- emoji: 🐢
4
  colorFrom: purple
5
- colorTo: pink
 
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: SynthWave Studio 🎹
 
3
  colorFrom: purple
4
+ colorTo: green
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
components/footer.js ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ footer {
7
+ background: #1f2937;
8
+ color: #9ca3af;
9
+ padding: 2rem;
10
+ text-align: center;
11
+ margin-top: auto;
12
+ border-top: 1px solid #374151;
13
+ }
14
+ .footer-content {
15
+ max-width: 1200px;
16
+ margin: 0 auto;
17
+ display: flex;
18
+ flex-direction: column;
19
+ align-items: center;
20
+ }
21
+ .social-links {
22
+ display: flex;
23
+ gap: 1rem;
24
+ margin: 1rem 0;
25
+ }
26
+ .social-links a {
27
+ color: #6b7280;
28
+ transition: color 0.2s;
29
+ }
30
+ .social-links a:hover {
31
+ color: white;
32
+ }
33
+ .copyright {
34
+ font-size: 0.875rem;
35
+ }
36
+ @media (max-width: 768px) {
37
+ footer {
38
+ padding: 1.5rem;
39
+ }
40
+ }
41
+ </style>
42
+ <footer>
43
+ <div class="footer-content">
44
+ <div class="social-links">
45
+ <a href="#" aria-label="GitHub"><i data-feather="github"></i></a>
46
+ <a href="#" aria-label="Twitter"><i data-feather="twitter"></i></a>
47
+ <a href="#" aria-label="YouTube"><i data-feather="youtube"></i></a>
48
+ </div>
49
+ <p class="copyright">&copy; 2023 SynthWave Studio. All rights reserved.</p>
50
+ <p class="copyright text-xs mt-2">Powered by Tone.js</p>
51
+ </div>
52
+ </footer>
53
+ `;
54
+
55
+ // Wait for feather icons to load
56
+ setTimeout(() => {
57
+ if (typeof feather !== 'undefined') {
58
+ feather.replace();
59
+ }
60
+ }, 100);
61
+ }
62
+ }
63
+ customElements.define('custom-footer', CustomFooter);
components/navbar.js ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomNavbar extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ nav {
7
+ background: linear-gradient(90deg, #1f2937 0%, #111827 100%);
8
+ padding: 1rem 2rem;
9
+ display: flex;
10
+ justify-content: space-between;
11
+ align-items: center;
12
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
13
+ border-bottom: 1px solid #374151;
14
+ }
15
+ .logo {
16
+ color: white;
17
+ font-weight: bold;
18
+ font-size: 1.5rem;
19
+ font-family: 'Orbitron', sans-serif;
20
+ display: flex;
21
+ align-items: center;
22
+ }
23
+ .logo i {
24
+ margin-right: 0.5rem;
25
+ color: #6b7280;
26
+ }
27
+ ul {
28
+ display: flex;
29
+ gap: 1.5rem;
30
+ list-style: none;
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+ a {
35
+ color: #d1d5db;
36
+ text-decoration: none;
37
+ font-weight: 500;
38
+ transition: all 0.2s ease;
39
+ padding: 0.5rem 1rem;
40
+ border-radius: 0.375rem;
41
+ }
42
+ a:hover {
43
+ color: white;
44
+ background-color: rgba(107, 114, 128, 0.2);
45
+ }
46
+ .active {
47
+ color: white;
48
+ background-color: rgba(107, 114, 128, 0.3);
49
+ }
50
+ @media (max-width: 768px) {
51
+ nav {
52
+ flex-direction: column;
53
+ padding: 1rem;
54
+ }
55
+ ul {
56
+ margin-top: 1rem;
57
+ flex-wrap: wrap;
58
+ justify-content: center;
59
+ }
60
+ }
61
+ </style>
62
+ <nav>
63
+ <div class="logo">
64
+ <i data-feather="music"></i>
65
+ <span>SynthWave Studio</span>
66
+ </div>
67
+ <ul>
68
+ <li><a href="/" class="active">Synthesizer</a></li>
69
+ <li><a href="/presets.html">Presets</a></li>
70
+ <li><a href="/sequencer.html">Sequencer</a></li>
71
+ <li><a href="/about.html">About</a></li>
72
+ </ul>
73
+ </nav>
74
+ `;
75
+
76
+ // Wait for feather icons to load
77
+ setTimeout(() => {
78
+ if (typeof feather !== 'undefined') {
79
+ feather.replace();
80
+ }
81
+ }, 100);
82
+ }
83
+ }
84
+ customElements.define('custom-navbar', CustomNavbar);
index.html CHANGED
@@ -1,19 +1,156 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SynthWave Studio</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ </head>
12
+ <body class="bg-gray-900 text-white min-h-screen">
13
+ <custom-navbar></custom-navbar>
14
+
15
+ <div class="container mx-auto px-4 py-8">
16
+ <header class="text-center mb-12">
17
+ <h1 class="text-4xl md:text-6xl font-bold mb-4 bg-gradient-to-r from-gray-400 to-white bg-clip-text text-transparent">
18
+ SynthWave Studio
19
+ </h1>
20
+ <p class="text-gray-400 text-lg max-w-2xl mx-auto">
21
+ Polyphonic MIDI synthesizer with velocity-sensitive controls, filters, and effects
22
+ </p>
23
+ </header>
24
+
25
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-12">
26
+ <!-- Synthesizer Controls -->
27
+ <div class="lg:col-span-2 bg-gray-800 rounded-xl p-6 shadow-2xl">
28
+ <h2 class="text-2xl font-bold mb-6 text-gray-300 flex items-center">
29
+ <i data-feather="sliders" class="mr-2"></i> Synthesizer Controls
30
+ </h2>
31
+
32
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
33
+ <!-- Oscillator Section -->
34
+ <div class="bg-gray-700 rounded-lg p-4">
35
+ <h3 class="font-semibold mb-3 text-gray-300">Oscillator</h3>
36
+ <div class="space-y-4">
37
+ <div>
38
+ <label class="block text-sm text-gray-400 mb-1">Type</label>
39
+ <select id="oscillator-type" class="w-full bg-gray-600 text-white rounded p-2">
40
+ <option value="sawtooth">Sawtooth</option>
41
+ <option value="sine">Sine</option>
42
+ <option value="square">Square</option>
43
+ <option value="triangle">Triangle</option>
44
+ </select>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <!-- Filter Section -->
50
+ <div class="bg-gray-700 rounded-lg p-4">
51
+ <h3 class="font-semibold mb-3 text-gray-300">Filter</h3>
52
+ <div class="space-y-4">
53
+ <div>
54
+ <label class="block text-sm text-gray-400 mb-1">Cutoff Frequency</label>
55
+ <input type="range" id="filter-frequency" min="50" max="5000" value="1000" step="1"
56
+ class="w-full accent-gray-500">
57
+ <span id="filter-frequency-value" class="text-xs text-gray-400">1000 Hz</span>
58
+ </div>
59
+ <div>
60
+ <label class="block text-sm text-gray-400 mb-1">Resonance</label>
61
+ <input type="range" id="filter-q" min="0.1" max="10" value="1" step="0.1"
62
+ class="w-full accent-gray-500">
63
+ <span id="filter-q-value" class="text-xs text-gray-400">1.0</span>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Envelope Section -->
69
+ <div class="bg-gray-700 rounded-lg p-4">
70
+ <h3 class="font-semibold mb-3 text-gray-300">Envelope</h3>
71
+ <div class="space-y-4">
72
+ <div>
73
+ <label class="block text-sm text-gray-400 mb-1">Attack</label>
74
+ <input type="range" id="envelope-attack" min="0.01" max="2" value="0.1" step="0.01"
75
+ class="w-full accent-gray-500">
76
+ <span id="envelope-attack-value" class="text-xs text-gray-400">0.1 s</span>
77
+ </div>
78
+ <div>
79
+ <label class="block text-sm text-gray-400 mb-1">Release</label>
80
+ <input type="range" id="envelope-release" min="0.1" max="5" value="0.5" step="0.1"
81
+ class="w-full accent-gray-500">
82
+ <span id="envelope-release-value" class="text-xs text-gray-400">0.5 s</span>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <!-- Effects Section -->
88
+ <div class="bg-gray-700 rounded-lg p-4">
89
+ <h3 class="font-semibold mb-3 text-gray-300">Effects</h3>
90
+ <div class="space-y-4">
91
+ <div>
92
+ <label class="block text-sm text-gray-400 mb-1">Reverb</label>
93
+ <input type="range" id="reverb-wet" min="0" max="1" value="0.3" step="0.01"
94
+ class="w-full accent-gray-500">
95
+ <span id="reverb-wet-value" class="text-xs text-gray-400">30%</span>
96
+ </div>
97
+ <div>
98
+ <label class="block text-sm text-gray-400 mb-1">Distortion</label>
99
+ <input type="range" id="distortion-wet" min="0" max="1" value="0.2" step="0.01"
100
+ class="w-full accent-gray-500">
101
+ <span id="distortion-wet-value" class="text-xs text-gray-400">20%</span>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- MIDI Connection Panel -->
109
+ <div class="bg-gray-800 rounded-xl p-6 shadow-2xl">
110
+ <h2 class="text-2xl font-bold mb-6 text-gray-300 flex items-center">
111
+ <i data-feather="music" class="mr-2"></i> MIDI Connection
112
+ </h2>
113
+
114
+ <div class="mb-6">
115
+ <button id="midi-connect-btn" class="w-full bg-gray-700 hover:bg-gray-600 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center">
116
+ <i data-feather="power" class="mr-2"></i> Connect MIDI Device
117
+ </button>
118
+ </div>
119
+
120
+ <div class="bg-gray-700 rounded-lg p-4 mb-6">
121
+ <h3 class="font-semibold mb-3 text-gray-300">MIDI Status</h3>
122
+ <div id="midi-status" class="text-sm text-yellow-400">
123
+ Not connected
124
+ </div>
125
+ </div>
126
+
127
+ <div class="bg-gray-700 rounded-lg p-4">
128
+ <h3 class="font-semibold mb-3 text-gray-300">Active Notes</h3>
129
+ <div id="active-notes" class="text-sm text-gray-400 h-32 overflow-y-auto">
130
+ No active notes
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+
136
+ <!-- Visualizer -->
137
+ <div class="bg-gray-800 rounded-xl p-6 shadow-2xl mb-12">
138
+ <h2 class="text-2xl font-bold mb-6 text-gray-300 flex items-center">
139
+ <i data-feather="activity" class="mr-2"></i> Audio Visualizer
140
+ </h2>
141
+ <canvas id="visualizer" class="w-full h-48 bg-gray-900 rounded-lg"></canvas>
142
+ </div>
143
+ </div>
144
+
145
+ <custom-footer></custom-footer>
146
+
147
+ <script src="components/navbar.js"></script>
148
+ <script src="components/footer.js"></script>
149
+ <script src="https://unpkg.com/tone@14.7.77/build/Tone.js"></script>
150
+ <script src="script.js"></script>
151
+ <script>
152
+ feather.replace();
153
+ </script>
154
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
155
+ </body>
156
+ </html>
presets.html ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sound Presets - SynthWave Studio</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ </head>
12
+ <body class="bg-gray-900 text-white min-h-screen">
13
+ <custom-navbar></custom-navbar>
14
+
15
+ <div class="container mx-auto px-4 py-8">
16
+ <header class="text-center mb-12">
17
+ <h1 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-gray-400 to-white bg-clip-text text-transparent">
18
+ Sound Presets
19
+ </h1>
20
+ <p class="text-gray-400 text-lg max-w-2xl mx-auto">
21
+ Explore and save your favorite synthesizer configurations
22
+ </p>
23
+ </header>
24
+
25
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
26
+ <!-- Preset Cards -->
27
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
28
+ <div class="flex justify-between items-start mb-4">
29
+ <h3 class="text-xl font-bold">Classic Saw</h3>
30
+ <button class="text-gray-400 hover:text-white">
31
+ <i data-feather="heart"></i>
32
+ </button>
33
+ </div>
34
+ <p class="text-gray-400 mb-4">Bright sawtooth wave with subtle reverb</p>
35
+ <div class="flex justify-between items-center">
36
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">Lead</span>
37
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
38
+ Load
39
+ </button>
40
+ </div>
41
+ </div>
42
+
43
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
44
+ <div class="flex justify-between items-start mb-4">
45
+ <h3 class="text-xl font-bold">Bass Growl</h3>
46
+ <button class="text-gray-400 hover:text-white">
47
+ <i data-feather="heart"></i>
48
+ </button>
49
+ </div>
50
+ <p class="text-gray-400 mb-4">Deep filtered bass with distortion</p>
51
+ <div class="flex justify-between items-center">
52
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">Bass</span>
53
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
54
+ Load
55
+ </button>
56
+ </div>
57
+ </div>
58
+
59
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
60
+ <div class="flex justify-between items-start mb-4">
61
+ <h3 class="text-xl font-bold">Pad Atmosphere</h3>
62
+ <button class="text-gray-400 hover:text-white">
63
+ <i data-feather="heart"></i>
64
+ </button>
65
+ </div>
66
+ <p class="text-gray-400 mb-4">Ambient pad with long release</p>
67
+ <div class="flex justify-between items-center">
68
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">Pad</span>
69
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
70
+ Load
71
+ </button>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
76
+ <div class="flex justify-between items-start mb-4">
77
+ <h3 class="text-xl font-bold">Analog Lead</h3>
78
+ <button class="text-gray-400 hover:text-white">
79
+ <i data-feather="heart"></i>
80
+ </button>
81
+ </div>
82
+ <p class="text-gray-400 mb-4">Warm analog-style lead sound</p>
83
+ <div class="flex justify-between items-center">
84
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">Lead</span>
85
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
86
+ Load
87
+ </button>
88
+ </div>
89
+ </div>
90
+
91
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
92
+ <div class="flex justify-between items-start mb-4">
93
+ <h3 class="text-xl font-bold">FM Bell</h3>
94
+ <button class="text-gray-400 hover:text-white">
95
+ <i data-feather="heart"></i>
96
+ </button>
97
+ </div>
98
+ <p class="text-gray-400 mb-4">Percussive bell-like timbre</p>
99
+ <div class="flex justify-between items-center">
100
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">FX</span>
101
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
102
+ Load
103
+ </button>
104
+ </div>
105
+ </div>
106
+
107
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
108
+ <div class="flex justify-between items-start mb-4">
109
+ <h3 class="text-xl font-bold">Arp Sequence</h3>
110
+ <button class="text-gray-400 hover:text-white">
111
+ <i data-feather="heart"></i>
112
+ </button>
113
+ </div>
114
+ <p class="text-gray-400 mb-4">Sequence-ready arpeggiated sound</p>
115
+ <div class="flex justify-between items-center">
116
+ <span class="text-sm bg-gray-700 px-2 py-1 rounded">Sequence</span>
117
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition">
118
+ Load
119
+ </button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <div class="bg-gray-800 rounded-xl p-6 shadow-lg">
125
+ <h2 class="text-2xl font-bold mb-6 flex items-center">
126
+ <i data-feather="plus-circle" class="mr-2"></i> Save Current Settings
127
+ </h2>
128
+ <form class="space-y-4">
129
+ <div>
130
+ <label class="block text-gray-300 mb-2">Preset Name</label>
131
+ <input type="text" placeholder="My Awesome Sound"
132
+ class="w-full bg-gray-700 text-white rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-gray-500">
133
+ </div>
134
+ <div>
135
+ <label class="block text-gray-300 mb-2">Category</label>
136
+ <select class="w-full bg-gray-700 text-white rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-gray-500">
137
+ <option>Bass</option>
138
+ <option>Lead</option>
139
+ <option>Pad</option>
140
+ <option>FX</option>
141
+ <option>Sequence</option>
142
+ </select>
143
+ </div>
144
+ <div>
145
+ <label class="block text-gray-300 mb-2">Description</label>
146
+ <textarea placeholder="Describe your sound..." rows="3"
147
+ class="w-full bg-gray-700 text-white rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-gray-500"></textarea>
148
+ </div>
149
+ <button type="submit" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition w-full">
150
+ Save Preset
151
+ </button>
152
+ </form>
153
+ </div>
154
+ </div>
155
+
156
+ <custom-footer></custom-footer>
157
+
158
+ <script src="components/navbar.js"></script>
159
+ <script src="components/footer.js"></script>
160
+ <script>
161
+ feather.replace();
162
+ </script>
163
+ </body>
164
+ </html>
script.js ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Shared JavaScript across all pages
2
+ console.log('SynthWave Studio loaded');
3
+
4
+ // Tone.js setup
5
+ let synth;
6
+ let filter;
7
+ let reverb;
8
+ let distortion;
9
+ let analyser;
10
+ let activeNotes = new Map();
11
+
12
+ // Initialize audio context on first interaction
13
+ let audioContextStarted = false;
14
+
15
+ function initAudioContext() {
16
+ if (!audioContextStarted) {
17
+ Tone.start();
18
+ audioContextStarted = true;
19
+ console.log('Audio context started');
20
+ }
21
+ }
22
+
23
+ // Setup Tone.js components
24
+ function setupSynth() {
25
+ // Create effects
26
+ reverb = new Tone.Reverb({
27
+ decay: 2,
28
+ wet: 0.3
29
+ }).toDestination();
30
+
31
+ distortion = new Tone.Distortion({
32
+ distortion: 0.2,
33
+ wet: 0.2
34
+ }).connect(reverb);
35
+
36
+ // Create filter
37
+ filter = new Tone.Filter({
38
+ type: "lowpass",
39
+ frequency: 1000,
40
+ Q: 1
41
+ }).connect(distortion);
42
+
43
+ // Create main synth
44
+ synth = new Tone.PolySynth(Tone.Synth, {
45
+ oscillator: {
46
+ type: "sawtooth"
47
+ },
48
+ envelope: {
49
+ attack: 0.1,
50
+ decay: 0.2,
51
+ sustain: 0.3,
52
+ release: 0.5
53
+ }
54
+ }).connect(filter);
55
+
56
+ // Create analyzer for visualizer
57
+ analyser = new Tone.Analyser("fft", 32);
58
+ synth.connect(analyser);
59
+
60
+ console.log('Synth initialized');
61
+ }
62
+
63
+ // MIDI handling
64
+ let midiAccess = null;
65
+ let midiInputs = [];
66
+
67
+ function onMIDISuccess(midi) {
68
+ midiAccess = midi;
69
+ updateMIDIStatus('Connected');
70
+ document.getElementById('midi-connect-btn').textContent = 'MIDI Connected';
71
+ document.getElementById('midi-connect-btn').disabled = true;
72
+
73
+ // Get inputs
74
+ const inputs = midi.inputs.values();
75
+ for (let input = inputs.next(); input && !input.done; input = inputs.next()) {
76
+ setupMIDIInput(input.value);
77
+ }
78
+
79
+ // Listen for new devices
80
+ midi.addEventListener('statechange', onMIDIStateChange);
81
+ }
82
+
83
+ function onMIDIFailure(msg) {
84
+ console.error('Failed to get MIDI access - ' + msg);
85
+ updateMIDIStatus('Connection failed: ' + msg, 'error');
86
+ }
87
+
88
+ function onMIDIStateChange(event) {
89
+ const port = event.port;
90
+ if (port.state === "connected") {
91
+ if (port.type === "input") {
92
+ setupMIDIInput(port);
93
+ }
94
+ } else if (port.state === "disconnected") {
95
+ if (port.type === "input") {
96
+ removeMIDIInput(port);
97
+ }
98
+ }
99
+ }
100
+
101
+ function setupMIDIInput(input) {
102
+ midiInputs.push(input);
103
+ input.addEventListener('midimessage', onMIDIMessage);
104
+ updateMIDIStatus(`Connected to: ${input.name}`, 'success');
105
+ }
106
+
107
+ function removeMIDIInput(input) {
108
+ midiInputs = midiInputs.filter(i => i.id !== input.id);
109
+ updateMIDIStatus(`Disconnected: ${input.name}`, 'warning');
110
+ }
111
+
112
+ function onMIDIMessage(message) {
113
+ const command = message.data[0];
114
+ const note = message.data[1];
115
+ const velocity = message.data[2];
116
+
117
+ switch (command) {
118
+ case 144: // Note on
119
+ if (velocity > 0) {
120
+ noteOn(note, velocity);
121
+ } else {
122
+ noteOff(note);
123
+ }
124
+ break;
125
+ case 128: // Note off
126
+ noteOff(note);
127
+ break;
128
+ }
129
+
130
+ updateActiveNotesDisplay();
131
+ }
132
+
133
+ function noteOn(note, velocity) {
134
+ if (!synth) return;
135
+
136
+ const noteName = Tone.Frequency(note, "midi").toNote();
137
+ const velocityNorm = velocity / 127;
138
+
139
+ synth.triggerAttack(noteName, undefined, velocityNorm);
140
+ activeNotes.set(note, { name: noteName, velocity: velocity });
141
+
142
+ console.log(`Note On: ${noteName}, Velocity: ${velocity}`);
143
+ }
144
+
145
+ function noteOff(note) {
146
+ if (!synth) return;
147
+
148
+ const noteName = Tone.Frequency(note, "midi").toNote();
149
+ synth.triggerRelease(noteName);
150
+ activeNotes.delete(note);
151
+
152
+ console.log(`Note Off: ${noteName}`);
153
+ }
154
+
155
+ function updateActiveNotesDisplay() {
156
+ const container = document.getElementById('active-notes');
157
+ if (activeNotes.size === 0) {
158
+ container.innerHTML = '<div class="text-gray-500">No active notes</div>';
159
+ return;
160
+ }
161
+
162
+ let html = '';
163
+ activeNotes.forEach((note, key) => {
164
+ html += `<div class="py-1 px-2 rounded mb-1 bg-gray-600 flex justify-between">
165
+ <span>${note.name}</span>
166
+ <span class="text-gray-400">Velocity: ${note.velocity}</span>
167
+ </div>`;
168
+ });
169
+ container.innerHTML = html;
170
+ }
171
+
172
+ function updateMIDIStatus(message, type = 'info') {
173
+ const statusEl = document.getElementById('midi-status');
174
+ statusEl.textContent = message;
175
+
176
+ statusEl.className = '';
177
+ switch(type) {
178
+ case 'success':
179
+ statusEl.classList.add('text-green-400');
180
+ break;
181
+ case 'warning':
182
+ statusEl.classList.add('text-yellow-400');
183
+ break;
184
+ case 'error':
185
+ statusEl.classList.add('text-red-400');
186
+ break;
187
+ default:
188
+ statusEl.classList.add('text-blue-400');
189
+ }
190
+ }
191
+
192
+ // UI Control Updates
193
+ function setupUIControls() {
194
+ // Oscillator Type
195
+ document.getElementById('oscillator-type').addEventListener('change', (e) => {
196
+ if (synth) {
197
+ synth.set({ oscillator: { type: e.target.value } });
198
+ }
199
+ });
200
+
201
+ // Filter Frequency
202
+ document.getElementById('filter-frequency').addEventListener('input', (e) => {
203
+ const value = parseInt(e.target.value);
204
+ document.getElementById('filter-frequency-value').textContent = `${value} Hz`;
205
+ if (filter) {
206
+ filter.frequency.value = value;
207
+ }
208
+ });
209
+
210
+ // Filter Resonance (Q)
211
+ document.getElementById('filter-q').addEventListener('input', (e) => {
212
+ const value = parseFloat(e.target.value);
213
+ document.getElementById('filter-q-value').textContent = value.toFixed(1);
214
+ if (filter) {
215
+ filter.Q.value = value;
216
+ }
217
+ });
218
+
219
+ // Envelope Attack
220
+ document.getElementById('envelope-attack').addEventListener('input', (e) => {
221
+ const value = parseFloat(e.target.value);
222
+ document.getElementById('envelope-attack-value').textContent = `${value.toFixed(2)} s`;
223
+ if (synth) {
224
+ synth.set({ envelope: { attack: value } });
225
+ }
226
+ });
227
+
228
+ // Envelope Release
229
+ document.getElementById('envelope-release').addEventListener('input', (e) => {
230
+ const value = parseFloat(e.target.value);
231
+ document.getElementById('envelope-release-value').textContent = `${value.toFixed(1)} s`;
232
+ if (synth) {
233
+ synth.set({ envelope: { release: value } });
234
+ }
235
+ });
236
+
237
+ // Reverb Wet
238
+ document.getElementById('reverb-wet').addEventListener('input', (e) => {
239
+ const value = parseFloat(e.target.value);
240
+ document.getElementById('reverb-wet-value').textContent = `${Math.round(value * 100)}%`;
241
+ if (reverb) {
242
+ reverb.wet.value = value;
243
+ }
244
+ });
245
+
246
+ // Distortion Wet
247
+ document.getElementById('distortion-wet').addEventListener('input', (e) => {
248
+ const value = parseFloat(e.target.value);
249
+ document.getElementById('distortion-wet-value').textContent = `${Math.round(value * 100)}%`;
250
+ if (distortion) {
251
+ distortion.wet.value = value;
252
+ }
253
+ });
254
+ }
255
+
256
+ // Visualizer
257
+ function setupVisualizer() {
258
+ const canvas = document.getElementById('visualizer');
259
+ const ctx = canvas.getContext('2d');
260
+
261
+ function resizeCanvas() {
262
+ canvas.width = canvas.clientWidth;
263
+ canvas.height = canvas.clientHeight;
264
+ }
265
+
266
+ window.addEventListener('resize', resizeCanvas);
267
+ resizeCanvas();
268
+
269
+ function draw() {
270
+ if (!analyser) {
271
+ requestAnimationFrame(draw);
272
+ return;
273
+ }
274
+
275
+ const values = analyser.getValue();
276
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
277
+
278
+ // Draw gradient background
279
+ const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
280
+ gradient.addColorStop(0, 'rgba(107, 114, 128, 0.2)');
281
+ gradient.addColorStop(1, 'rgba(107, 114, 128, 0.05)');
282
+ ctx.fillStyle = gradient;
283
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
284
+
285
+ // Draw waveform
286
+ ctx.beginPath();
287
+ ctx.lineWidth = 2;
288
+ ctx.strokeStyle = '#6b7280'; // gray-500
289
+
290
+ const sliceWidth = canvas.width / values.length;
291
+ let x = 0;
292
+
293
+ for (let i = 0; i < values.length; i++) {
294
+ const v = (values[i] + 1) / 2;
295
+ const y = v * canvas.height;
296
+
297
+ if (i === 0) {
298
+ ctx.moveTo(x, y);
299
+ } else {
300
+ ctx.lineTo(x, y);
301
+ }
302
+
303
+ x += sliceWidth;
304
+ }
305
+
306
+ ctx.stroke();
307
+ requestAnimationFrame(draw);
308
+ }
309
+
310
+ draw();
311
+ }
312
+
313
+ // Initialize everything when page loads
314
+ document.addEventListener('DOMContentLoaded', () => {
315
+ // Setup UI controls
316
+ setupUIControls();
317
+
318
+ // Setup visualizer
319
+ setupVisualizer();
320
+
321
+ // Setup synth
322
+ setupSynth();
323
+
324
+ // MIDI connection button
325
+ document.getElementById('midi-connect-btn').addEventListener('click', () => {
326
+ initAudioContext();
327
+ if (navigator.requestMIDIAccess) {
328
+ navigator.requestMIDIAccess()
329
+ .then(onMIDISuccess, onMIDIFailure);
330
+ } else {
331
+ updateMIDIStatus('WebMIDI is not supported in this browser', 'error');
332
+ }
333
+ });
334
+ });
sequencer.html ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sequencer - SynthWave Studio</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ </head>
12
+ <body class="bg-gray-900 text-white min-h-screen">
13
+ <custom-navbar></custom-navbar>
14
+
15
+ <div class="container mx-auto px-4 py-8">
16
+ <header class="text-center mb-12">
17
+ <h1 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-gray-400 to-white bg-clip-text text-transparent">
18
+ Sequencer
19
+ </h1>
20
+ <p class="text-gray-400 text-lg max-w-2xl mx-auto">
21
+ Create patterns and sequences with your synthesizer
22
+ </p>
23
+ </header>
24
+
25
+ <div class="bg-gray-800 rounded-xl p-6 shadow-2xl mb-8">
26
+ <div class="flex flex-wrap justify-between items-center mb-6">
27
+ <div class="flex items-center space-x-4 mb-4 md:mb-0">
28
+ <button id="play-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-3 rounded-full">
29
+ <i data-feather="play"></i>
30
+ </button>
31
+ <button id="stop-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-3 rounded-full">
32
+ <i data-feather="square"></i>
33
+ </button>
34
+ <div class="flex items-center">
35
+ <span class="mr-2 text-gray-400">Tempo:</span>
36
+ <input type="number" id="tempo" value="120" min="40" max="240"
37
+ class="w-20 bg-gray-700 text-white rounded p-2 text-center">
38
+ </div>
39
+ </div>
40
+ <div class="flex space-x-2">
41
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
42
+ <i data-feather="save" class="mr-1"></i> Save
43
+ </button>
44
+ <button class="bg-gray-700 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
45
+ <i data-feather="download" class="mr-1"></i> Export
46
+ </button>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="overflow-x-auto">
51
+ <table class="w-full">
52
+ <thead>
53
+ <tr>
54
+ <th class="p-2 text-left text-gray-400">Step</th>
55
+ <th class="p-2 text-center" colspan="16">Sequence</th>
56
+ </tr>
57
+ </thead>
58
+ <tbody>
59
+ <tr>
60
+ <td class="p-2 text-gray-400">C4</td>
61
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
62
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
63
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
64
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
65
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
66
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
67
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
68
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
69
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
70
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
71
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
72
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
73
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
74
+ <td class="p-1"><button class="w-full h-8 bg-gray-700 hover:bg-gray-600 rounded"></button></td>
75
+ <...... NEW_FILE_START about.html >>>>>>> NEW_FILE_END
76
+ </body>
77
+ </html>
style.css CHANGED
@@ -1,28 +1,121 @@
 
 
 
 
 
 
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
 
 
 
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
 
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Shared styles across all pages */
2
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&family=Roboto:wght@300;400;500;700&display=swap');
3
+
4
+ :root {
5
+ --primary-color: #6b7280; /* gray-500 */
6
+ --secondary-color: #ffffff; /* white */
7
+ }
8
+
9
  body {
10
+ font-family: 'Roboto', sans-serif;
11
+ background-color: #111827; /* gray-900 */
12
+ color: var(--secondary-color);
13
+ margin: 0;
14
+ padding: 0;
15
+ min-height: 100vh;
16
+ display: flex;
17
+ flex-direction: column;
18
+ }
19
+
20
+ h1, h2, h3, h4, h5, h6 {
21
+ font-family: 'Orbitron', sans-serif;
22
+ }
23
+
24
+ .container {
25
+ max-width: 1400px;
26
+ }
27
+
28
+ /* Custom scrollbar */
29
+ ::-webkit-scrollbar {
30
+ width: 8px;
31
+ }
32
+
33
+ ::-webkit-scrollbar-track {
34
+ background: #1f2937; /* gray-800 */
35
+ }
36
+
37
+ ::-webkit-scrollbar-thumb {
38
+ background: var(--primary-color);
39
+ border-radius: 4px;
40
+ }
41
+
42
+ ::-webkit-scrollbar-thumb:hover {
43
+ background: #4b5563; /* gray-600 */
44
+ }
45
+
46
+ /* Button styles */
47
+ button {
48
+ transition: all 0.2s ease;
49
+ }
50
+
51
+ button:hover {
52
+ transform: translateY(-2px);
53
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
54
+ }
55
+
56
+ /* Input range styling */
57
+ input[type="range"] {
58
+ -webkit-appearance: none;
59
+ height: 8px;
60
+ border-radius: 4px;
61
+ background: #374151; /* gray-700 */
62
+ outline: none;
63
  }
64
 
65
+ input[type="range"]::-webkit-slider-thumb {
66
+ -webkit-appearance: none;
67
+ width: 20px;
68
+ height: 20px;
69
+ border-radius: 50%;
70
+ background: var(--primary-color);
71
+ cursor: pointer;
72
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
73
  }
74
 
75
+ input[type="range"]::-moz-range-thumb {
76
+ width: 20px;
77
+ height: 20px;
78
+ border-radius: 50%;
79
+ background: var(--primary-color);
80
+ cursor: pointer;
81
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
82
+ border: none;
83
  }
84
 
85
+ /* Select styling */
86
+ select {
87
+ appearance: none;
88
+ background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
89
+ background-repeat: no-repeat;
90
+ background-position: right 0.5rem center;
91
+ background-size: 1em;
92
  }
93
 
94
+ /* Canvas styling */
95
+ #visualizer {
96
+ width: 100%;
97
+ height: 192px;
98
+ background: #111827; /* gray-900 */
99
+ border-radius: 0.5rem;
100
  }
101
+
102
+ /* Active note styling */
103
+ .note-active {
104
+ background-color: #374151 !important; /* gray-700 */
105
+ border-left: 3px solid var(--primary-color);
106
+ }
107
+
108
+ /* Responsive adjustments */
109
+ @media (max-width: 768px) {
110
+ .container {
111
+ padding: 0 1rem;
112
+ }
113
+
114
+ h1 {
115
+ font-size: 2rem;
116
+ }
117
+
118
+ .grid {
119
+ gap: 1rem;
120
+ }
121
+ }