erl-j commited on
Commit
f644682
·
1 Parent(s): 155a8f3

fix lightmode/darkmode issue amongst other things

Browse files
Files changed (4) hide show
  1. app.py +14 -17
  2. custom.css +144 -116
  3. custom.js +47 -28
  4. hero.html +18 -0
app.py CHANGED
@@ -109,23 +109,19 @@ def generate_and_export_soundfont(text, steps=20, instrument_name=None):
109
  custom_js = open("custom.js").read()
110
  custom_css = open("custom.css").read()
111
 
112
- demo = gr.Blocks(title="Erl-j's sound font generator", js=custom_js,
 
 
 
 
 
113
  css = custom_css)
114
 
115
- with demo:
116
- gr.Markdown("""
117
- # Erl-j's Soundfont Generator.
118
- Generate soundfonts from text descriptions using latent flow matching. You can then download the complete SFZ soundfont package to use the instrument locally.
119
- ## Instructions
120
- 1. Enter a text prompt to describe the audio you want to generate. For example, *"hard bass"* or *"dark analog lead flute flute flute soft"*.
121
- 2. Adjust the number of generation steps to tradeoff between quality and speed (kindof).
122
- 3. Click the "Generate Soundfont" button to generate the audio and soundfont.
123
- 4. Preview the generated instrument with the keyboard.
124
- 5. Export the soundfont by clicking the "Download SFZ Soundfont Package" button. You can then use the soundfont in a SFZ-compatible sampler. See [this list](https://sfzformat.com/software/players/) for a list of SFZ players.
125
- """)
126
-
127
-
128
-
129
  with gr.Row():
130
  steps = gr.Slider(
131
  minimum=1, maximum=50, value=20, step=1, label="Generation steps"
@@ -137,6 +133,7 @@ with demo:
137
  placeholder="Enter text description (e.g. 'hard bass', 'sparkly bells')",
138
  lines=2,
139
  )
 
140
 
141
  with gr.Row():
142
  generate_btn = gr.Button("Generate Soundfont", variant="primary")
@@ -150,11 +147,11 @@ with demo:
150
 
151
  html = """
152
  <div id="custom-player"
153
- style="width: 100%; height: 600px; background-color: "red"; border: 1px solid #f8f9fa; border-radius: 5px; margin-top: 10px;"
154
  ></div>
155
  """
156
 
157
- gr.HTML(html, min_height=800, max_height=800)
158
 
159
  gr.Markdown("## Download Soundfont Package here:")
160
  with gr.Row():
 
109
  custom_js = open("custom.js").read()
110
  custom_css = open("custom.css").read()
111
 
112
+ demo = gr.Blocks(title="Erl-j's Soundfont Generator",
113
+ theme = gr.themes.Default(
114
+ primary_hue="green",
115
+ font=[gr.themes.GoogleFont("Inconsolata"), "Arial", "sans-serif"]
116
+ ),
117
+ js=custom_js,
118
  css = custom_css)
119
 
120
+ with demo:
121
+ hero_html = open("hero.html").read()
122
+
123
+ gr.HTML(hero_html)
124
+
 
 
 
 
 
 
 
 
 
125
  with gr.Row():
126
  steps = gr.Slider(
127
  minimum=1, maximum=50, value=20, step=1, label="Generation steps"
 
133
  placeholder="Enter text description (e.g. 'hard bass', 'sparkly bells')",
134
  lines=2,
135
  )
136
+
137
 
138
  with gr.Row():
139
  generate_btn = gr.Button("Generate Soundfont", variant="primary")
 
147
 
148
  html = """
149
  <div id="custom-player"
150
+ style="width: 100%; height: 600px; background-color: "white"; border: 1px solid #f8f9fa; border-radius: 5px; margin-top: 10px;"
151
  ></div>
152
  """
153
 
154
+ gr.HTML(html, min_height=1000, max_height=1000)
155
 
156
  gr.Markdown("## Download Soundfont Package here:")
157
  with gr.Row():
custom.css CHANGED
@@ -1,12 +1,66 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
 
3
  .keyboard-container {
4
  width: 100%;
5
  padding: 1.5rem;
6
- background: #fafafa;
7
- border: 1px solid #e5e5e5;
8
  border-radius: 4px;
9
- font-family: 'Roboto', sans-serif;
10
  user-select: none;
11
  }
12
 
@@ -17,26 +71,26 @@
17
  width: 100%;
18
  }
19
 
 
20
  .key {
21
  width: calc((100% - 2.75rem) / 12);
22
  aspect-ratio: 1;
23
  min-width: 40px;
24
  flex: none;
25
- border: 1px solid #e5e5e5;
 
26
  border-radius: 4px;
 
 
 
27
  display: flex;
28
  flex-direction: column;
29
  align-items: center;
30
  justify-content: center;
31
- cursor: pointer;
32
- background: white;
33
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
34
- user-select: none;
35
- padding: 0.5rem;
36
  }
37
 
38
  .key:hover {
39
- background: #f5f5f5;
40
  transform: translateY(-1px);
41
  }
42
 
@@ -44,160 +98,134 @@
44
  transform: translateY(0);
45
  }
46
 
 
 
 
 
 
47
  .key-label {
48
  font-size: 0.875rem;
49
  font-weight: 500;
50
- color: #333;
51
- user-select: none;
52
  }
53
 
54
  .note-label {
55
  font-size: 0.75rem;
56
- color: #666;
57
  margin-top: 0.25rem;
58
- user-select: none;
59
  }
60
 
61
- .controls {
 
 
 
 
 
 
62
  display: flex;
63
- flex-wrap: wrap;
64
- gap: 1rem;
65
- margin-bottom: 1.5rem;
66
- }
67
-
68
- .effects-controls {
69
- display: grid;
70
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
71
- gap: 1rem;
72
- margin-bottom: 1.5rem;
73
- padding: 1rem;
74
- background: #fafafa;
75
- border-radius: 4px;
76
  }
77
 
78
  .control-group {
79
- display: flex;
80
- flex-direction: column;
81
- gap: 0.5rem;
82
  }
83
 
84
- .control-group label {
85
- font-size: 0.75rem;
86
- color: #666;
87
- text-transform: uppercase;
88
- letter-spacing: 0.05em;
89
- user-select: none;
 
 
 
 
 
 
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  input[type="range"] {
93
  width: 100%;
94
- height: 24px; /* Increased height for better touch target */
95
- background: transparent; /* Remove default background */
96
  border-radius: 2px;
97
  appearance: none;
98
  cursor: pointer;
99
- margin: 0;
100
- padding: 10px 0; /* Add padding for better touch area */
101
  }
102
 
103
  input[type="range"]::-webkit-slider-thumb {
104
  appearance: none;
105
- width: 24px; /* Increased size */
106
- height: 24px; /* Increased size */
107
- background: #000000;
108
  border-radius: 50%;
109
  cursor: pointer;
110
- transition: background 0.2s;
111
- margin-top: -10px; /* Center thumb vertically */
112
- user-select: none;
113
  }
114
 
115
  input[type="range"]::-webkit-slider-runnable-track {
116
- background: #393a39;
117
  height: 4px;
118
  border-radius: 2px;
119
- user-select: none;
120
  }
121
 
122
- select {
123
- padding: 0.5rem;
124
- border-radius: 4px;
125
- border: 1px solid #e5e5e5;
126
- background: white;
127
- font-family: 'Roboto', sans-serif;
128
- font-size: 0.875rem;
129
- user-select: none;
130
- cursor: pointer;
131
- }
132
-
133
- .button-group {
134
- display: flex;
135
- align-items: center;
136
- gap: 0.5rem;
137
- }
138
-
139
- .button-group button {
140
- width: 2rem;
141
- height: 2rem;
142
- padding: 0;
143
- display: flex;
144
- align-items: center;
145
- justify-content: center;
146
- border: 1px solid #e5e5e5;
147
- border-radius: 4px;
148
- background: white;
149
- cursor: pointer;
150
- transition: all 0.2s;
151
- user-select: none;
152
- }
153
-
154
- .button-group button:hover {
155
- background: #f5f5f5;
156
- }
157
-
158
- button {
159
- padding: 0.5rem 1rem;
160
  border: none;
161
- border-radius: 4px;
162
- background: #015131;
163
- color: white;
164
- font-family: 'Roboto', sans-serif;
165
- font-size: 0.875rem;
166
  cursor: pointer;
167
- transition: all 0.2s;
168
- user-select: none;
169
- }
170
-
171
- button:hover {
172
- background: #002114;
173
  }
174
 
175
- body {
176
- font-family: 'Roboto', sans-serif;
177
- font-size: 1rem;
178
- line-height: 1.5;
179
- color: #333;
180
- background: #f5f5f5;
181
- margin: 0;
182
- padding: 0;
183
- display: flex;
184
- justify-content: center;
185
- align-items: center;
186
- min-height: 100vh;
187
  }
188
 
 
189
  @media (max-width: 768px) {
190
- .control-group { min-width: 100%; }
191
- .key { min-width: 35px; }
192
- .key-label { font-size: 0.75rem; }
 
 
 
 
 
 
 
 
193
 
194
  input[type="range"] {
195
- height: 32px; /* Even larger touch target on mobile */
196
  padding: 14px 0;
197
  }
198
 
199
  input[type="range"]::-webkit-slider-thumb {
200
- width: 28px; /* Larger thumb on mobile */
201
  height: 28px;
202
  }
203
  }
 
1
+ /* CSS Variables */
2
+ :root {
3
+ /* Light mode */
4
+ --background-color: #f5f5f5;
5
+ --container-background: #fafafa;
6
+ --key-background: white;
7
+ --key-hover-background: #f5f5f5;
8
+ --border-color: #e5e5e5;
9
+ --text-primary: #333;
10
+ --text-secondary: #666;
11
+ --slider-track: #393a39;
12
+ --slider-thumb: #000000;
13
+ --button-background: #015131;
14
+ --button-hover: #002114;
15
+ --button-text: white;
16
+ --keyboard-bg: #fafafa;
17
+ --inactive-key-bg: #e0e0e0;
18
+ }
19
+
20
+ @media (prefers-color-scheme: dark) {
21
+ :root {
22
+ --background-color: #121212;
23
+ --container-background: #1e1e1e;
24
+ --key-background: #2d2d2d;
25
+ --key-hover-background: #3d3d3d;
26
+ --border-color: #404040;
27
+ --text-primary: #e0e0e0;
28
+ --text-secondary: #a0a0a0;
29
+ --slider-track: #666666;
30
+ --slider-thumb: #015131;
31
+ --button-background: #015131;
32
+ --button-hover: #026b41;
33
+ --keyboard-bg: #1e1e1e;
34
+ --inactive-key-bg: #2d2d2d;
35
+ }
36
+ }
37
+
38
+ /* Base styles */
39
+ html, body, #root, .wrapper, main, .main-container {
40
+ background-color: var(--background-color);
41
+ min-height: 100vh;
42
+ margin: 0;
43
+ padding: 0;
44
+ width: 100%;
45
+ max-width: 100%;
46
+ }
47
+
48
+ body {
49
+ font-family: 'Roboto', sans-serif;
50
+ font-size: 1rem;
51
+ line-height: 1.5;
52
+ color: var(--text-primary);
53
+ overflow-x: hidden;
54
+ transition: background-color 0.2s ease;
55
+ }
56
 
57
+ /* Keyboard layout */
58
  .keyboard-container {
59
  width: 100%;
60
  padding: 1.5rem;
61
+ background: var(--keyboard-bg);
62
+ border: 1px solid var(--border-color);
63
  border-radius: 4px;
 
64
  user-select: none;
65
  }
66
 
 
71
  width: 100%;
72
  }
73
 
74
+ /* Key styles */
75
  .key {
76
  width: calc((100% - 2.75rem) / 12);
77
  aspect-ratio: 1;
78
  min-width: 40px;
79
  flex: none;
80
+ padding: 0.5rem;
81
+ border: 1px solid var(--border-color);
82
  border-radius: 4px;
83
+ background: var(--key-background);
84
+ cursor: pointer;
85
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
86
  display: flex;
87
  flex-direction: column;
88
  align-items: center;
89
  justify-content: center;
 
 
 
 
 
90
  }
91
 
92
  .key:hover {
93
+ background: var(--key-hover-background);
94
  transform: translateY(-1px);
95
  }
96
 
 
98
  transform: translateY(0);
99
  }
100
 
101
+ .key.inactive,
102
+ .key:disabled {
103
+ background: var(--inactive-key-bg);
104
+ }
105
+
106
  .key-label {
107
  font-size: 0.875rem;
108
  font-weight: 500;
109
+ color: var(--text-primary);
 
110
  }
111
 
112
  .note-label {
113
  font-size: 0.75rem;
114
+ color: var(--text-secondary);
115
  margin-top: 0.25rem;
 
116
  }
117
 
118
+ /* Controls section */
119
+ .controls-section {
120
+ margin: 1em 0;
121
+ padding: 1em;
122
+ }
123
+
124
+ .controls-row {
125
  display: flex;
126
+ gap: 1em;
127
+ margin: 1em 0;
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
  .control-group {
131
+ margin: 1em 0;
 
 
132
  }
133
 
134
+ .control-group.half-width {
135
+ flex: 1;
136
+ margin: 0;
137
+ }
138
+
139
+ /* Labels and values */
140
+ .slider-label,
141
+ h3 {
142
+ display: block;
143
+ margin-bottom: 0.5em;
144
+ font-size: 0.9em;
145
+ color: var(--text-primary);
146
  }
147
 
148
+ h3 {
149
+ margin-top: 0;
150
+ font-size: 1rem;
151
+ font-weight: 500;
152
+ }
153
+
154
+ .slider-value,
155
+ .master-value,
156
+ .release-value,
157
+ .reverb-mix-value,
158
+ .root-value,
159
+ .column-value,
160
+ .row-value {
161
+ color: var(--text-secondary);
162
+ font-weight: 500;
163
+ }
164
+
165
+ /* Range inputs */
166
  input[type="range"] {
167
  width: 100%;
168
+ height: 24px;
169
+ background: transparent;
170
  border-radius: 2px;
171
  appearance: none;
172
  cursor: pointer;
173
+ margin: 0.5em 0;
174
+ padding: 10px 0;
175
  }
176
 
177
  input[type="range"]::-webkit-slider-thumb {
178
  appearance: none;
179
+ width: 16px;
180
+ height: 16px;
181
+ background: var(--slider-thumb);
182
  border-radius: 50%;
183
  cursor: pointer;
184
+ margin-top: -6px;
 
 
185
  }
186
 
187
  input[type="range"]::-webkit-slider-runnable-track {
188
+ background: var(--slider-track);
189
  height: 4px;
190
  border-radius: 2px;
 
191
  }
192
 
193
+ input[type="range"]::-moz-range-thumb {
194
+ width: 16px;
195
+ height: 16px;
196
+ background: var(--slider-thumb);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  border: none;
198
+ border-radius: 50%;
 
 
 
 
199
  cursor: pointer;
 
 
 
 
 
 
200
  }
201
 
202
+ input[type="range"]::-moz-range-track {
203
+ background: var(--slider-track);
204
+ height: 4px;
205
+ border-radius: 2px;
 
 
 
 
 
 
 
 
206
  }
207
 
208
+ /* Mobile styles */
209
  @media (max-width: 768px) {
210
+ .control-group {
211
+ min-width: 100%;
212
+ }
213
+
214
+ .key {
215
+ min-width: 35px;
216
+ }
217
+
218
+ .key-label {
219
+ font-size: 0.75rem;
220
+ }
221
 
222
  input[type="range"] {
223
+ height: 32px;
224
  padding: 14px 0;
225
  }
226
 
227
  input[type="range"]::-webkit-slider-thumb {
228
+ width: 28px;
229
  height: 28px;
230
  }
231
  }
custom.js CHANGED
@@ -5,7 +5,7 @@ function previewPlayer() {
5
  this.initializeProperties();
6
  this.loadToneJS().then(() => this.init());
7
  this.setupWavFileObserver();
8
-
9
 
10
  // Add click handlers for activation/deactivation
11
  this.container.addEventListener('click', (e) => {
@@ -71,6 +71,7 @@ function previewPlayer() {
71
  this.rowOffset = 4;
72
  this.activeNotes = new Map();
73
  this.reverb = null;
 
74
  this.releaseTime = 0.1;
75
  this.noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
76
  this.majorScale = [0, 2, 4, 5, 7, 9, 11];
@@ -98,32 +99,39 @@ function previewPlayer() {
98
  createUI() {
99
  this.container.innerHTML = `
100
  <div class="keyboard-container">
101
- <div class="effects-controls">
102
- <h3>Release & Reverb</h3>
103
- <div class="effect-slider">
104
- <label>Release: <span class="release-value">0.1s</span></label>
105
- <input type="range" class="release-slider" min="0" max="3" step="0.1" value="0.1">
106
  </div>
107
- <div class="effect-slider">
108
- <label>Reverb: <span class="reverb-value">50%</span></label>
109
- <input type="range" class="reverb-slider" min="0" max="100" value="50">
 
 
 
 
 
 
110
  </div>
111
  </div>
112
  <div class="keyboard"></div>
113
- <br>
114
- <div class="mapping-controls">
115
  <h3>Keyboard Mapping</h3>
116
  <div class="control-group">
117
- <label>Root Pitch: <span class="root-value">C4</span></label>
118
- <input type="range" class="root-slider" min="24" max="84" value="60">
119
  </div>
120
- <div class="control-group">
121
- <label>Column Offset: <span class="column-value">2</span> keys from left</label>
122
- <input type="range" class="column-slider" min="0" max="6" value="2">
123
- </div>
124
- <div class="control-group">
125
- <label>Row Offset: <span class="row-value">4</span> scale degree(s)</label>
126
- <input type="range" class="row-slider" min="1" max="20" value="4">
 
 
127
  </div>
128
  </div>
129
  </div>
@@ -134,6 +142,8 @@ function previewPlayer() {
134
  cacheElements() {
135
  const selectors = {
136
  keyboard: '.keyboard',
 
 
137
  rootSlider: '.root-slider',
138
  rootValue: '.root-value',
139
  columnSlider: '.column-slider',
@@ -142,26 +152,31 @@ function previewPlayer() {
142
  rowValue: '.row-value',
143
  releaseSlider: '.release-slider',
144
  releaseValue: '.release-value',
145
- reverbSlider: '.reverb-slider',
146
- reverbValue: '.reverb-value'
147
  };
148
  this.elements = Object.fromEntries(
149
  Object.entries(selectors).map(([key, selector]) =>
150
  [key, this.container.querySelector(selector)]
151
  )
152
  );
153
- }
154
 
155
  setupEventListeners() {
156
  const handlers = {
 
 
 
 
 
157
  releaseSlider: e => {
158
  this.releaseTime = parseFloat(e.target.value);
159
  this.elements.releaseValue.textContent = `${this.releaseTime}s`;
160
  },
161
- reverbSlider: e => {
162
  const wetness = parseInt(e.target.value) / 100;
163
  this.reverb.wet.value = wetness;
164
- this.elements.reverbValue.textContent = `${e.target.value}%`;
165
  },
166
  rootSlider: e => {
167
  this.rootPitch = parseInt(e.target.value);
@@ -189,9 +204,13 @@ function previewPlayer() {
189
  }
190
 
191
  initializeEffects() {
192
- this.reverb = new Tone.Reverb({ decay: 1.5, wet: 0.5 }).toDestination();
 
 
 
 
 
193
  }
194
-
195
  async initializeSampler() {
196
  const availableNotes = ['C1', 'F#1', 'C2', 'F#2', 'C3', 'F#3', 'C4', 'F#4', 'C5', 'F#5'];
197
  const urls = Object.fromEntries(
@@ -213,7 +232,7 @@ function previewPlayer() {
213
 
214
  handleSamplerError() {
215
  console.log('No WAV files found');
216
-
217
  }
218
 
219
  handleSamplerLoad() {
 
5
  this.initializeProperties();
6
  this.loadToneJS().then(() => this.init());
7
  this.setupWavFileObserver();
8
+
9
 
10
  // Add click handlers for activation/deactivation
11
  this.container.addEventListener('click', (e) => {
 
71
  this.rowOffset = 4;
72
  this.activeNotes = new Map();
73
  this.reverb = null;
74
+ this.masterGain = null;
75
  this.releaseTime = 0.1;
76
  this.noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
77
  this.majorScale = [0, 2, 4, 5, 7, 9, 11];
 
99
  createUI() {
100
  this.container.innerHTML = `
101
  <div class="keyboard-container">
102
+ <div class="controls-section">
103
+ <h3>Master & Effects</h3>
104
+ <div class="control-group">
105
+ <label class="slider-label">Release: <span class="release-value">0.1s</span></label>
106
+ <input type="range" class="control-slider release-slider" min="0" max="3" step="0.1" value="0.1">
107
  </div>
108
+ <div class="controls-row">
109
+ <div class="control-group half-width">
110
+ <label class="slider-label">Reverb Mix: <span class="reverb-mix-value">20%</span></label>
111
+ <input type="range" class="control-slider reverb-mix-slider" min="0" max="100" value="20">
112
+ </div>
113
+ <div class="control-group half-width">
114
+ <label class="slider-label">Master: <span class="master-value">100%</span></label>
115
+ <input type="range" class="control-slider master-slider" min="0" max="200" value="100">
116
+ </div>
117
  </div>
118
  </div>
119
  <div class="keyboard"></div>
120
+ <div class="controls-section">
 
121
  <h3>Keyboard Mapping</h3>
122
  <div class="control-group">
123
+ <label class="slider-label">Root Pitch: <span class="root-value">C4</span></label>
124
+ <input type="range" class="control-slider root-slider" min="24" max="84" value="60">
125
  </div>
126
+ <div class="controls-row">
127
+ <div class="control-group half-width">
128
+ <label class="slider-label">Column Offset: <span class="column-value">2</span> keys</label>
129
+ <input type="range" class="control-slider column-slider" min="0" max="6" value="2">
130
+ </div>
131
+ <div class="control-group half-width">
132
+ <label class="slider-label">Row Offset: <span class="row-value">4</span> degrees</label>
133
+ <input type="range" class="control-slider row-slider" min="1" max="20" value="4">
134
+ </div>
135
  </div>
136
  </div>
137
  </div>
 
142
  cacheElements() {
143
  const selectors = {
144
  keyboard: '.keyboard',
145
+ masterSlider: '.master-slider',
146
+ masterValue: '.master-value',
147
  rootSlider: '.root-slider',
148
  rootValue: '.root-value',
149
  columnSlider: '.column-slider',
 
152
  rowValue: '.row-value',
153
  releaseSlider: '.release-slider',
154
  releaseValue: '.release-value',
155
+ reverbMixSlider: '.reverb-mix-slider',
156
+ reverbMixValue: '.reverb-mix-value'
157
  };
158
  this.elements = Object.fromEntries(
159
  Object.entries(selectors).map(([key, selector]) =>
160
  [key, this.container.querySelector(selector)]
161
  )
162
  );
163
+ };
164
 
165
  setupEventListeners() {
166
  const handlers = {
167
+ masterSlider: e => {
168
+ const gain = parseInt(e.target.value) / 100;
169
+ this.masterGain.gain.value = gain;
170
+ this.elements.masterValue.textContent = `${e.target.value}%`;
171
+ },
172
  releaseSlider: e => {
173
  this.releaseTime = parseFloat(e.target.value);
174
  this.elements.releaseValue.textContent = `${this.releaseTime}s`;
175
  },
176
+ reverbMixSlider: e => {
177
  const wetness = parseInt(e.target.value) / 100;
178
  this.reverb.wet.value = wetness;
179
+ this.elements.reverbMixValue.textContent = `${e.target.value}%`;
180
  },
181
  rootSlider: e => {
182
  this.rootPitch = parseInt(e.target.value);
 
204
  }
205
 
206
  initializeEffects() {
207
+ this.masterGain = new Tone.Gain(1).toDestination();
208
+ this.reverb = new Tone.Reverb({
209
+ decay: 1.5,
210
+ wet: 0.5,
211
+ preDelay: 0.01
212
+ }).connect(this.masterGain);
213
  }
 
214
  async initializeSampler() {
215
  const availableNotes = ['C1', 'F#1', 'C2', 'F#2', 'C3', 'F#3', 'C4', 'F#4', 'C5', 'F#5'];
216
  const urls = Object.fromEntries(
 
232
 
233
  handleSamplerError() {
234
  console.log('No WAV files found');
235
+
236
  }
237
 
238
  handleSamplerLoad() {
hero.html ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div>
2
+ <h1>Erl-j's Soundfont Generator</h1>
3
+ Generate soundfonts from text descriptions using latent flow matching. You can then download the complete SFZ
4
+ soundfont
5
+ package to use the instrument locally.
6
+ <h2>Instructions</h2>
7
+ 1. Enter a text prompt to describe the audio you want to generate. For example, *"hard bass"* or *"dark analog lead
8
+ flute flute flute soft"*.
9
+ <br>
10
+ 2. Adjust the number of generation steps to tradeoff between quality and speed (kindof).
11
+ <br>
12
+ 3. Click the "Generate Soundfont" button to generate the audio and soundfont.
13
+ <br>
14
+ 4. Preview the generated instrument with the keyboard.
15
+ <br>
16
+ 5. Export the soundfont by clicking the "Download SFZ Soundfont Package" button. You can then use the soundfont in a
17
+ SFZ-compatible sampler. See [this list](https://sfzformat.com/software/players/) for a list of SFZ players.
18
+ </div>