Spaces:
Sleeping
Sleeping
new MidiVisualizer
Browse files- app.py +3 -2
- javascript/app.js +181 -35
- midi_synthesizer.py +1 -1
app.py
CHANGED
@@ -424,9 +424,10 @@ if __name__ == "__main__":
|
|
424 |
with gr.Accordion("options", open=False):
|
425 |
input_temp = gr.Slider(label="temperature", minimum=0.1, maximum=1.2, step=0.01, value=1)
|
426 |
input_top_p = gr.Slider(label="top p", minimum=0.1, maximum=1, step=0.01, value=0.98)
|
427 |
-
input_top_k = gr.Slider(label="top k", minimum=1, maximum=128, step=1, value=
|
428 |
input_allow_cc = gr.Checkbox(label="allow midi cc event", value=True)
|
429 |
-
example3 = gr.Examples([[1, 0.
|
|
|
430 |
run_btn = gr.Button("generate", variant="primary")
|
431 |
stop_btn = gr.Button("stop and output")
|
432 |
output_midi_seq = gr.State()
|
|
|
424 |
with gr.Accordion("options", open=False):
|
425 |
input_temp = gr.Slider(label="temperature", minimum=0.1, maximum=1.2, step=0.01, value=1)
|
426 |
input_top_p = gr.Slider(label="top p", minimum=0.1, maximum=1, step=0.01, value=0.98)
|
427 |
+
input_top_k = gr.Slider(label="top k", minimum=1, maximum=128, step=1, value=12)
|
428 |
input_allow_cc = gr.Checkbox(label="allow midi cc event", value=True)
|
429 |
+
example3 = gr.Examples([[1, 0.95, 128], [1, 0.98, 20], [1, 0.98, 12]],
|
430 |
+
[input_temp, input_top_p, input_top_k])
|
431 |
run_btn = gr.Button("generate", variant="primary")
|
432 |
stop_btn = gr.Button("stop and output")
|
433 |
output_midi_seq = gr.State()
|
javascript/app.js
CHANGED
@@ -98,14 +98,22 @@ function HSVtoRGB(h, s, v) {
|
|
98 |
};
|
99 |
}
|
100 |
|
|
|
|
|
|
|
101 |
class MidiVisualizer extends HTMLElement{
|
102 |
constructor() {
|
103 |
super();
|
104 |
this.midiEvents = [];
|
105 |
this.activeNotes = [];
|
106 |
this.midiTimes = [];
|
107 |
-
this.
|
108 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
109 |
this.svg = null;
|
110 |
this.timeLine = null;
|
111 |
this.config = {
|
@@ -130,40 +138,167 @@ class MidiVisualizer extends HTMLElement{
|
|
130 |
this.innerHTML=''
|
131 |
const shadow = this.attachShadow({mode: 'open'});
|
132 |
const style = document.createElement("style");
|
133 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
style.textContent = ".note.active {stroke: black;stroke-width: 0.75;stroke-opacity: 0.75;}";
|
135 |
-
|
|
|
136 |
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
137 |
svg.style.height = `${this.config.noteHeight*128}px`;
|
138 |
svg.style.width = `${this.svgWidth}px`;
|
139 |
const timeLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
140 |
timeLine.style.stroke = "green"
|
141 |
timeLine.style.strokeWidth = 2;
|
|
|
142 |
shadow.appendChild(style)
|
143 |
-
shadow.appendChild(
|
144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
svg.appendChild(timeLine)
|
146 |
-
this.
|
|
|
147 |
this.svg = svg;
|
148 |
this.timeLine= timeLine;
|
149 |
-
for(let i = 0; i
|
150 |
-
this.colorMap.set(i, HSVtoRGB(i /
|
151 |
}
|
152 |
-
console.log(this.colorMap)
|
153 |
this.setPlayTime(0);
|
154 |
}
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
clearMidiEvents(){
|
157 |
this.pause()
|
158 |
this.midiEvents = [];
|
159 |
this.activeNotes = [];
|
160 |
this.midiTimes = [];
|
161 |
-
this.
|
|
|
|
|
|
|
|
|
162 |
this.t1 = 0
|
163 |
this.setPlayTime(0);
|
164 |
this.totalTimeMs = 0;
|
165 |
this.playTimeMs = 0
|
166 |
this.lastUpdateTime = 0
|
|
|
167 |
this.svgWidth = 0
|
168 |
this.svg.innerHTML = ''
|
169 |
this.svg.style.width = `${this.svgWidth}px`;
|
@@ -193,21 +328,24 @@ class MidiVisualizer extends HTMLElement{
|
|
193 |
velocity = midiEvent[5]
|
194 |
duration = midiEvent[6]
|
195 |
}
|
|
|
196 |
|
197 |
let x = (t/this.timePreBeat)*this.config.beatWidth
|
198 |
let y = (127 - pitch)*this.config.noteHeight
|
199 |
let w = (duration/this.timePreBeat)*this.config.beatWidth
|
200 |
let h = this.config.noteHeight
|
201 |
this.svgWidth = Math.ceil(Math.max(x + w, this.svgWidth))
|
202 |
-
let color =
|
203 |
let opacity = Math.min(1, velocity/127 + 0.1).toFixed(2)
|
204 |
-
let rect = this.drawNote(x,y,w,h,
|
|
|
205 |
midiEvent.push(rect)
|
206 |
this.setPlayTime(t);
|
207 |
-
this.
|
208 |
}else if(midiEvent[0] === "patch_change"){
|
209 |
let channel = midiEvent[3]
|
210 |
-
this.patches[channel]
|
|
|
211 |
}
|
212 |
this.midiEvents.push(midiEvent);
|
213 |
this.svg.style.width = `${this.svgWidth}px`;
|
@@ -215,23 +353,8 @@ class MidiVisualizer extends HTMLElement{
|
|
215 |
|
216 |
}
|
217 |
|
218 |
-
|
219 |
-
|
220 |
-
if( channel === 9){
|
221 |
-
// drum
|
222 |
-
key = 128;
|
223 |
-
}
|
224 |
-
let color = this.colorMap.get(key);
|
225 |
-
if(!!color){
|
226 |
-
return color;
|
227 |
-
}
|
228 |
-
color = HSVtoRGB(Math.random(),Math.random()*0.5 + 0.5,1);
|
229 |
-
this.colorMap.set(key, color);
|
230 |
-
return color;
|
231 |
-
}
|
232 |
-
|
233 |
-
drawNote(x, y, w, h, fill) {
|
234 |
-
if (!this.svg) {
|
235 |
return null;
|
236 |
}
|
237 |
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
@@ -242,7 +365,7 @@ class MidiVisualizer extends HTMLElement{
|
|
242 |
rect.setAttribute('y', `${Math.round(y)}`);
|
243 |
rect.setAttribute('width', `${Math.round(w)}`);
|
244 |
rect.setAttribute('height', `${Math.round(h)}`);
|
245 |
-
|
246 |
return rect
|
247 |
}
|
248 |
|
@@ -277,7 +400,30 @@ class MidiVisualizer extends HTMLElement{
|
|
277 |
this.timeLine.setAttribute('x2', `${x}`);
|
278 |
this.timeLine.setAttribute('y2', `${this.config.noteHeight*128}`);
|
279 |
|
280 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
let dt = Date.now() - this.lastUpdateTime; // limit the update rate of ActiveNotes
|
282 |
if(this.playing && dt > 50){
|
283 |
let activeNotes = []
|
@@ -291,7 +437,7 @@ class MidiVisualizer extends HTMLElement{
|
|
291 |
activeNotes.push(note)
|
292 |
}
|
293 |
}
|
294 |
-
})
|
295 |
this.addActiveNotes(activeNotes)
|
296 |
this.lastUpdateTime = Date.now();
|
297 |
}
|
|
|
98 |
};
|
99 |
}
|
100 |
|
101 |
+
const number2patch = ['Acoustic Grand', 'Bright Acoustic', 'Electric Grand', 'Honky-Tonk', 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clav', 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone', 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer', 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ', 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion', 'Acoustic Guitar(nylon)', 'Acoustic Guitar(steel)', 'Electric Guitar(jazz)', 'Electric Guitar(clean)', 'Electric Guitar(muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar Harmonics', 'Acoustic Bass', 'Electric Bass(finger)', 'Electric Bass(pick)', 'Fretless Bass', 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2', 'Violin', 'Viola', 'Cello', 'Contrabass', 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani', 'String Ensemble 1', 'String Ensemble 2', 'SynthStrings 1', 'SynthStrings 2', 'Choir Aahs', 'Voice Oohs', 'Synth Voice', 'Orchestra Hit', 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet', 'French Horn', 'Brass Section', 'SynthBrass 1', 'SynthBrass 2', 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax', 'Oboe', 'English Horn', 'Bassoon', 'Clarinet', 'Piccolo', 'Flute', 'Recorder', 'Pan Flute', 'Blown Bottle', 'Skakuhachi', 'Whistle', 'Ocarina', 'Lead 1 (square)', 'Lead 2 (sawtooth)', 'Lead 3 (calliope)', 'Lead 4 (chiff)', 'Lead 5 (charang)', 'Lead 6 (voice)', 'Lead 7 (fifths)', 'Lead 8 (bass+lead)', 'Pad 1 (new age)', 'Pad 2 (warm)', 'Pad 3 (polysynth)', 'Pad 4 (choir)', 'Pad 5 (bowed)', 'Pad 6 (metallic)', 'Pad 7 (halo)', 'Pad 8 (sweep)', 'FX 1 (rain)', 'FX 2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)', 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)', 'Sitar', 'Banjo', 'Shamisen', 'Koto', 'Kalimba', 'Bagpipe', 'Fiddle', 'Shanai', 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock', 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal', 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet', 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot']
|
102 |
+
const number2drum_kits = {0: "Standard", 8: "Room", 16: "Power", 24: "Electric", 25: "TR-808", 32: "Jazz", 40: "Blush", 48: "Orchestra"}
|
103 |
+
|
104 |
class MidiVisualizer extends HTMLElement{
|
105 |
constructor() {
|
106 |
super();
|
107 |
this.midiEvents = [];
|
108 |
this.activeNotes = [];
|
109 |
this.midiTimes = [];
|
110 |
+
this.trackMap = new Map()
|
111 |
+
this.patches = [];
|
112 |
+
for (let i=0;i<16;i++){
|
113 |
+
this.patches.push([[0,0]])
|
114 |
+
}
|
115 |
+
this.trackList = null
|
116 |
+
this.pianoRoll = null;
|
117 |
this.svg = null;
|
118 |
this.timeLine = null;
|
119 |
this.config = {
|
|
|
138 |
this.innerHTML=''
|
139 |
const shadow = this.attachShadow({mode: 'open'});
|
140 |
const style = document.createElement("style");
|
141 |
+
const container = document.createElement('div');
|
142 |
+
container.style.display="flex";
|
143 |
+
container.style.height=`${this.config.noteHeight*128}px`;
|
144 |
+
const trackListContainer = document.createElement('div');
|
145 |
+
trackListContainer.style.width = "260px";
|
146 |
+
trackListContainer.style.minWidth = "260px";
|
147 |
+
trackListContainer.style.height = "100%";
|
148 |
+
trackListContainer.style.display="flex";
|
149 |
+
trackListContainer.style.flexDirection="column";
|
150 |
+
const trackList = document.createElement('div');
|
151 |
+
trackList.style.width = "100%";
|
152 |
+
trackList.style.height = "100%";
|
153 |
+
trackList.style.overflowY= "scroll";
|
154 |
+
trackList.style.display="flex";
|
155 |
+
trackList.style.flexDirection="column";
|
156 |
+
trackList.style.flexGrow="1";
|
157 |
+
const trackControls = document.createElement('div');
|
158 |
+
trackControls.style.display="flex";
|
159 |
+
trackControls.style.flexDirection="row";
|
160 |
+
trackControls.style.width = "100%";
|
161 |
+
trackControls.style.height = "50px";
|
162 |
+
const allTrackBtn = document.createElement('button');
|
163 |
+
allTrackBtn.textContent = "All";
|
164 |
+
allTrackBtn.style.width = "50%";
|
165 |
+
allTrackBtn.style.height = "100%";
|
166 |
+
allTrackBtn.style.backgroundColor = "transparent";
|
167 |
+
allTrackBtn.style.border = "none";
|
168 |
+
allTrackBtn.style.cursor = 'pointer';
|
169 |
+
let self = this;
|
170 |
+
allTrackBtn.onclick = function (){
|
171 |
+
self.trackMap.forEach((track, id) => {
|
172 |
+
track.setChecked(true);
|
173 |
+
})
|
174 |
+
};
|
175 |
+
const noneTrackBtn = document.createElement('button');
|
176 |
+
noneTrackBtn.textContent = "None";
|
177 |
+
noneTrackBtn.style.width = "50%";
|
178 |
+
noneTrackBtn.style.height = "100%";
|
179 |
+
noneTrackBtn.style.backgroundColor = "transparent";
|
180 |
+
noneTrackBtn.style.border = "none";
|
181 |
+
noneTrackBtn.style.cursor = 'pointer';
|
182 |
+
noneTrackBtn.onclick = function (){
|
183 |
+
self.trackMap.forEach((track, id) => {
|
184 |
+
track.setChecked(false);
|
185 |
+
});
|
186 |
+
};
|
187 |
+
const pianoRoll = document.createElement('div');
|
188 |
style.textContent = ".note.active {stroke: black;stroke-width: 0.75;stroke-opacity: 0.75;}";
|
189 |
+
pianoRoll.style.overflowX= "scroll";
|
190 |
+
pianoRoll.style.flexGrow="1";
|
191 |
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
192 |
svg.style.height = `${this.config.noteHeight*128}px`;
|
193 |
svg.style.width = `${this.svgWidth}px`;
|
194 |
const timeLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
195 |
timeLine.style.stroke = "green"
|
196 |
timeLine.style.strokeWidth = 2;
|
197 |
+
|
198 |
shadow.appendChild(style)
|
199 |
+
shadow.appendChild(container);
|
200 |
+
container.appendChild(trackListContainer);
|
201 |
+
trackListContainer.appendChild(trackList);
|
202 |
+
trackListContainer.appendChild(trackControls);
|
203 |
+
trackControls.appendChild(allTrackBtn);
|
204 |
+
trackControls.appendChild(noneTrackBtn);
|
205 |
+
container.appendChild(pianoRoll);
|
206 |
+
pianoRoll.appendChild(svg);
|
207 |
svg.appendChild(timeLine)
|
208 |
+
this.trackList = trackList;
|
209 |
+
this.pianoRoll = pianoRoll;
|
210 |
this.svg = svg;
|
211 |
this.timeLine= timeLine;
|
212 |
+
for(let i = 0; i < 128 ; i++){
|
213 |
+
this.colorMap.set(i, HSVtoRGB(i / 128, 1, 1))
|
214 |
}
|
|
|
215 |
this.setPlayTime(0);
|
216 |
}
|
217 |
|
218 |
+
addTrack(id, tr, cl, name, color){
|
219 |
+
const track = {id, tr, cl, name, color,
|
220 |
+
instrument: cl===9?"Standard Drum":"Acoustic Grand",
|
221 |
+
svg: document.createElementNS('http://www.w3.org/2000/svg', 'g')}
|
222 |
+
this.svg.appendChild(track.svg)
|
223 |
+
const trackItem = this.createTrackItem(track);
|
224 |
+
this.trackList.appendChild(trackItem);
|
225 |
+
this.trackMap.set(id, track);
|
226 |
+
return track;
|
227 |
+
}
|
228 |
+
|
229 |
+
getTrack(tr, cl){
|
230 |
+
const id = tr * 16 + cl
|
231 |
+
let track = this.trackMap.get(id)
|
232 |
+
if (!!track){
|
233 |
+
return track
|
234 |
+
}
|
235 |
+
let color = this.colorMap.get((this.trackMap.size*17)%128)
|
236 |
+
return this.addTrack(id, tr, cl, `Track ${tr}, Channel ${cl}`, color)
|
237 |
+
}
|
238 |
+
|
239 |
+
createTrackItem(track) {
|
240 |
+
const trackItem = document.createElement('div');
|
241 |
+
trackItem.style.display = 'flex';
|
242 |
+
trackItem.style.alignItems = 'center';
|
243 |
+
trackItem.style.width = '100%';
|
244 |
+
trackItem.style.position = 'relative';
|
245 |
+
|
246 |
+
const colorBar = document.createElement('div');
|
247 |
+
colorBar.style.width = '5%';
|
248 |
+
colorBar.style.height = '100%';
|
249 |
+
colorBar.style.position = 'absolute';
|
250 |
+
colorBar.style.left = '0';
|
251 |
+
colorBar.style.top = '0';
|
252 |
+
let color = track.color;
|
253 |
+
colorBar.style.backgroundColor = `rgb(${color.r}, ${color.g}, ${color.b})`;
|
254 |
+
trackItem.appendChild(colorBar);
|
255 |
+
|
256 |
+
const content = document.createElement('div');
|
257 |
+
content.style.paddingLeft = '30px';
|
258 |
+
content.style.flexGrow = '1';
|
259 |
+
content.innerHTML = `<p>${track.name}<br>${track.instrument}</p>`;
|
260 |
+
trackItem.appendChild(content);
|
261 |
+
track.updateInstrument = function (instrument){
|
262 |
+
track.instrument = instrument;
|
263 |
+
content.innerHTML = `<p>${track.name}<br>${track.instrument}</p>`;
|
264 |
+
}
|
265 |
+
|
266 |
+
const toggleSwitch = document.createElement('input');
|
267 |
+
toggleSwitch.type = 'checkbox';
|
268 |
+
toggleSwitch.checked = true;
|
269 |
+
toggleSwitch.style.marginLeft = 'auto';
|
270 |
+
toggleSwitch.style.marginRight = '10px';
|
271 |
+
toggleSwitch.style.width = '20px';
|
272 |
+
toggleSwitch.style.height = '20px';
|
273 |
+
toggleSwitch.style.cursor = 'pointer';
|
274 |
+
|
275 |
+
toggleSwitch.onchange = function () {
|
276 |
+
track.svg.setAttribute('visibility',toggleSwitch.checked? "visible" : "hidden")
|
277 |
+
};
|
278 |
+
track.setChecked = function (checked){
|
279 |
+
toggleSwitch.checked = checked;
|
280 |
+
track.svg.setAttribute('visibility',toggleSwitch.checked? "visible" : "hidden")
|
281 |
+
}
|
282 |
+
trackItem.appendChild(toggleSwitch);
|
283 |
+
return trackItem;
|
284 |
+
}
|
285 |
+
|
286 |
clearMidiEvents(){
|
287 |
this.pause()
|
288 |
this.midiEvents = [];
|
289 |
this.activeNotes = [];
|
290 |
this.midiTimes = [];
|
291 |
+
this.trackMap = new Map()
|
292 |
+
this.patches = [];
|
293 |
+
for (let i=0;i<16;i++){
|
294 |
+
this.patches.push([[0,0]])
|
295 |
+
}
|
296 |
this.t1 = 0
|
297 |
this.setPlayTime(0);
|
298 |
this.totalTimeMs = 0;
|
299 |
this.playTimeMs = 0
|
300 |
this.lastUpdateTime = 0
|
301 |
+
this.trackList.innerHTML = ''
|
302 |
this.svgWidth = 0
|
303 |
this.svg.innerHTML = ''
|
304 |
this.svg.style.width = `${this.svgWidth}px`;
|
|
|
328 |
velocity = midiEvent[5]
|
329 |
duration = midiEvent[6]
|
330 |
}
|
331 |
+
let vis_track = this.getTrack(track, channel);
|
332 |
|
333 |
let x = (t/this.timePreBeat)*this.config.beatWidth
|
334 |
let y = (127 - pitch)*this.config.noteHeight
|
335 |
let w = (duration/this.timePreBeat)*this.config.beatWidth
|
336 |
let h = this.config.noteHeight
|
337 |
this.svgWidth = Math.ceil(Math.max(x + w, this.svgWidth))
|
338 |
+
let color = vis_track.color
|
339 |
let opacity = Math.min(1, velocity/127 + 0.1).toFixed(2)
|
340 |
+
let rect = this.drawNote(vis_track.svg, x,y,w,h,
|
341 |
+
`rgba(${color.r}, ${color.g}, ${color.b}, ${opacity})`)
|
342 |
midiEvent.push(rect)
|
343 |
this.setPlayTime(t);
|
344 |
+
this.pianoRoll.scrollTo(this.svgWidth - this.pianoRoll.offsetWidth, this.pianoRoll.scrollTop)
|
345 |
}else if(midiEvent[0] === "patch_change"){
|
346 |
let channel = midiEvent[3]
|
347 |
+
this.patches[channel].push([t, midiEvent[4]])
|
348 |
+
this.patches[channel].sort((a, b) => a[0] - b[0])
|
349 |
}
|
350 |
this.midiEvents.push(midiEvent);
|
351 |
this.svg.style.width = `${this.svgWidth}px`;
|
|
|
353 |
|
354 |
}
|
355 |
|
356 |
+
drawNote(svg, x, y, w, h, fill) {
|
357 |
+
if (!svg) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
return null;
|
359 |
}
|
360 |
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
|
365 |
rect.setAttribute('y', `${Math.round(y)}`);
|
366 |
rect.setAttribute('width', `${Math.round(w)}`);
|
367 |
rect.setAttribute('height', `${Math.round(h)}`);
|
368 |
+
svg.appendChild(rect);
|
369 |
return rect
|
370 |
}
|
371 |
|
|
|
400 |
this.timeLine.setAttribute('x2', `${x}`);
|
401 |
this.timeLine.setAttribute('y2', `${this.config.noteHeight*128}`);
|
402 |
|
403 |
+
this.pianoRoll.scrollTo(Math.max(0, x - this.pianoRoll.offsetWidth/2), this.pianoRoll.scrollTop)
|
404 |
+
|
405 |
+
this.trackMap.forEach((track, id)=>{
|
406 |
+
let instrument = track.instrument
|
407 |
+
let cl = track.cl;
|
408 |
+
let patches = this.patches[cl]
|
409 |
+
let p = 0
|
410 |
+
for (let i = 0; i < patches.length ; i++){
|
411 |
+
let tp = patches[i]
|
412 |
+
if (t < tp[0])
|
413 |
+
break
|
414 |
+
p = tp[1]
|
415 |
+
}
|
416 |
+
if (cl === 9){
|
417 |
+
let drumKit = number2drum_kits[`${p}`];
|
418 |
+
if (!!drumKit)
|
419 |
+
instrument = drumKit + " Drum";
|
420 |
+
}else{
|
421 |
+
instrument = number2patch[p]
|
422 |
+
}
|
423 |
+
if (instrument !== track.instrument)
|
424 |
+
track.updateInstrument(instrument)
|
425 |
+
});
|
426 |
+
|
427 |
let dt = Date.now() - this.lastUpdateTime; // limit the update rate of ActiveNotes
|
428 |
if(this.playing && dt > 50){
|
429 |
let activeNotes = []
|
|
|
437 |
activeNotes.push(note)
|
438 |
}
|
439 |
}
|
440 |
+
});
|
441 |
this.addActiveNotes(activeNotes)
|
442 |
this.lastUpdateTime = Date.now();
|
443 |
}
|
midi_synthesizer.py
CHANGED
@@ -22,8 +22,8 @@ class MidiSynthesizer:
|
|
22 |
return device
|
23 |
|
24 |
def release_fluidsynth(self, device):
|
25 |
-
device[0].get_samples(self.sample_rate*5) # wait for silence
|
26 |
device[0].system_reset()
|
|
|
27 |
device[2] = False
|
28 |
|
29 |
def synthesis(self, midi_opus):
|
|
|
22 |
return device
|
23 |
|
24 |
def release_fluidsynth(self, device):
|
|
|
25 |
device[0].system_reset()
|
26 |
+
device[0].get_samples(self.sample_rate*5) # wait for silence
|
27 |
device[2] = False
|
28 |
|
29 |
def synthesis(self, midi_opus):
|