Skip to content

Commit 7c3eb13

Browse files
committed
new midi file
1 parent dd9fa0b commit 7c3eb13

File tree

2 files changed

+344
-344
lines changed

2 files changed

+344
-344
lines changed

js/activity.js

Lines changed: 3 additions & 344 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ if (_THIS_IS_MUSIC_BLOCKS_) {
173173
"widgets/sampler",
174174
"activity/lilypond",
175175
"activity/abc",
176+
"activity/midi",
176177
"activity/mxml"
177178
];
178179
MYDEFINES = MYDEFINES.concat(MUSICBLOCKS_EXTRAS);
@@ -4227,348 +4228,6 @@ class Activity {
42274228
return closest.value.split('/').map(Number);
42284229
}
42294230

4230-
this.transcribeMidi = async function(midi) {
4231-
4232-
const DRUM_MIDI_MAP = {
4233-
38: ["snare drum"],
4234-
36: ["kick drum"],
4235-
41: ["tom tom"],
4236-
43: ["floor tom tom"],
4237-
47: ["cup drum"],
4238-
50: ["darbuka drum"],
4239-
56: ["japanese drum", "cow bell"],
4240-
42: ["hi hat"],
4241-
53: ["ride bell"],
4242-
81: ["triangle bell"],
4243-
69: ["finger cymbals"],
4244-
82: ["chime"],
4245-
52: ["gong"],
4246-
55: ["clang"],
4247-
49: ["crash"],
4248-
39: ["clap"],
4249-
40: ["slap"],
4250-
88: ["raindrop"]
4251-
};
4252-
4253-
4254-
let currentMidi = midi;
4255-
let jsONON = [] ;
4256-
let actionBlockCounter = 0; // Counter for action blocks
4257-
let actionBlockNames = []; // Array to store action block names
4258-
let totalnoteblockCount = 0; // Initialize noteblock counter
4259-
let noteblockCount = 0;
4260-
const MAX_NOTEBLOCKS = 200;
4261-
let shortestNoteDenominator = 0;
4262-
let offset = 100;
4263-
let stopProcessing = false;
4264-
let trackCount = 0;
4265-
let actionBlockPerTrack = [];
4266-
let instruments = [];
4267-
let defaultTempo=90;
4268-
let currentMidiTempoBpm = currentMidi.header.tempos;
4269-
if (currentMidiTempoBpm && currentMidiTempoBpm.length > 0) {
4270-
currentMidiTempoBpm = Math.round(currentMidiTempoBpm[0].bpm);
4271-
} else {
4272-
currentMidiTempoBpm = defaultTempo;
4273-
}
4274-
4275-
let defaultTimeSignature = [4, 4];
4276-
let currentMidiTimeSignature = currentMidi.header.timeSignatures;
4277-
if (currentMidiTimeSignature && currentMidiTimeSignature.length > 0) {
4278-
currentMidiTimeSignature = currentMidiTimeSignature[0].timeSignature;
4279-
} else {
4280-
currentMidiTimeSignature = defaultTimeSignature;
4281-
}
4282-
4283-
let precurssionFlag = false;
4284-
const isPercussion=[];
4285-
// console.log("tempoBpm is: ", currentMidiTempoBpm);
4286-
// console.log("tempo is : ",currentMidi.header.tempos);
4287-
// console.log("time signatures are: ", currentMidi.header.timeSignatures);
4288-
console.log(currentMidi);
4289-
currentMidi.tracks.forEach((track, trackIndex) => {
4290-
let k = 0;
4291-
if (stopProcessing) return; // Exit if flag is set
4292-
if (!track.notes.length) return;
4293-
let r = jsONON.length;
4294-
// console.log("notes: ",track.notes);
4295-
// find matching instrument
4296-
let instrument = "electronic synth";
4297-
if (track.instrument.name && !track.instrument.percussion) {
4298-
for (let voices of VOICENAMES) {
4299-
if (track.instrument.name.indexOf(voices[1]) > -1) {
4300-
instrument = voices[0];
4301-
}
4302-
}
4303-
} else if (track.instrument.percussion) {
4304-
precurssionFlag = true;
4305-
}
4306-
actionBlockPerTrack[trackCount] = 0;
4307-
instruments[trackCount] = instrument;
4308-
4309-
let actionBlockName = `track${trackCount}chunk${actionBlockCounter}`;
4310-
4311-
jsONON.push(
4312-
[r, ["action", { collapsed: false }], 150, 100, [null, r+1, r+2, null]],
4313-
[r+1, ["text", { value: actionBlockName }], 0, 0, [r]]
4314-
);
4315-
4316-
let sched = [];
4317-
isPercussion.push(track.instrument.percussion && (track.channel === 9 || track.channel === 10));
4318-
4319-
track.notes.forEach((note, index) => {
4320-
let name = note.name;
4321-
let start = Math.round(note.time * 100) / 100;
4322-
let end = Math.round((note.time + note.duration) * 100) / 100;
4323-
4324-
if (note.duration === 0) return; // Skip zero-duration notes
4325-
4326-
let lastNote = sched[sched.length - 1];
4327-
4328-
if (index === 0 && start > 0) {
4329-
sched.push({ start: 0, end: start, notes: ["R"] });
4330-
}
4331-
4332-
if (lastNote && lastNote.start === start && lastNote.end === end) {
4333-
lastNote.notes.push(name);
4334-
return;
4335-
}
4336-
4337-
if (lastNote && lastNote.start <= start && lastNote.end > start) {
4338-
let prevNotes = [...lastNote.notes];
4339-
let oldEnd = lastNote.end;
4340-
4341-
lastNote.end = start;
4342-
4343-
sched.push({ start: start, end: end, notes: [...prevNotes, name] });
4344-
4345-
if (oldEnd > end) {
4346-
sched.push({ start: end, end: oldEnd, notes: prevNotes });
4347-
}
4348-
return;
4349-
}
4350-
4351-
if (lastNote && lastNote.end < start) {
4352-
sched.push({ start: lastNote.end, end: start, notes: ["R"] });
4353-
}
4354-
4355-
// Add the new note to the schedule
4356-
sched.push({ start: start, end: end, notes: [name] });
4357-
});
4358-
4359-
4360-
let noteSum = 0;
4361-
let currentActionBlock = [];
4362-
4363-
let addNewActionBlock = (isLastBlock=false) => {
4364-
let r = jsONON.length;
4365-
let actionBlockName = `track${trackCount}chunk${actionBlockCounter}`;
4366-
actionBlockNames.push(actionBlockName);
4367-
actionBlockPerTrack[trackCount]++;
4368-
if (k == 0) {
4369-
jsONON.push(
4370-
...currentActionBlock
4371-
);
4372-
k = 1;
4373-
} else {
4374-
let settimbreIndex = r;
4375-
// Adjust the first note block's top connection to settimbre
4376-
currentActionBlock[0][4][0] = settimbreIndex;
4377-
jsONON.push(
4378-
[r, ["action", { collapsed: false }], 100+offset, 100+offset, [null, r+1, settimbreIndex+2, null]],
4379-
[r+1, ["text", { value: actionBlockName }], 0, 0, [r]],
4380-
...currentActionBlock
4381-
);
4382-
4383-
}
4384-
if (isLastBlock) {
4385-
let lastIndex = jsONON.length - 1;
4386-
// Set the last hidden block's second value to null
4387-
jsONON[lastIndex][4][1] = null;
4388-
}
4389-
4390-
currentActionBlock = [];
4391-
actionBlockCounter++; // Increment the action block counter
4392-
offset+=100;
4393-
};
4394-
//Using for loop for finding the shortest note value
4395-
for (let j in sched) {
4396-
let st = sched[j].start;
4397-
let ed= sched[j].end;
4398-
let dur = ed - st;
4399-
let temp = this.getClosestStandardNoteValue(dur * 3 / 8);
4400-
shortestNoteDenominator=Math.max(shortestNoteDenominator,temp[1]);
4401-
}
4402-
4403-
for (let i in sched) {
4404-
if (stopProcessing) break; // Exit inner loop if flag is set
4405-
let { notes, start, end } = sched[i];
4406-
let duration = end - start;
4407-
noteSum += duration;
4408-
let isLastNoteInBlock = (noteSum >= 16) || (noteblockCount > 0 && noteblockCount % 24 === 0);
4409-
if (isLastNoteInBlock) {
4410-
totalnoteblockCount+=noteblockCount;
4411-
noteblockCount = 0;
4412-
noteSum = 0;
4413-
}
4414-
let isLastNoteInSched = (i == sched.length - 1);
4415-
let last = isLastNoteInBlock || isLastNoteInSched;
4416-
let first = (i == 0);
4417-
let val = jsONON.length + currentActionBlock.length;
4418-
let getPitch = (x, notes, prev) => {
4419-
let ar = [];
4420-
if (notes[0] == "R") {
4421-
ar.push(
4422-
[x, "rest2", 0, 0, [prev, null]]
4423-
);
4424-
} else if (precurssionFlag) {
4425-
let drumname = DRUM_MIDI_MAP[track.notes[0].midi][0] || "kick drum";
4426-
ar.push(
4427-
[x, "playdrum", 0, 0, [first ? prev : x-1, x+1, null]],
4428-
[x+1, ["drumname",{"value":drumname}], 0, 0,[x]],
4429-
);
4430-
x += 2;
4431-
} else {
4432-
for (let na in notes) {
4433-
let name = notes[na];
4434-
let first = na == 0;
4435-
let last = na == notes.length - 1;
4436-
ar.push(
4437-
[x, "pitch", 0, 0, [first ? prev : x-3, x+1, x+2, last ? null : x+3]],
4438-
[x+1, ["notename", {"value": name.substring(0, name.length-1)}], 0, 0, [x]],
4439-
[x+2, ["number", {"value": parseInt(name[name.length-1])}], 0, 0, [x]]
4440-
);
4441-
x += 3;
4442-
}
4443-
}
4444-
return ar;
4445-
};
4446-
let obj = this.getClosestStandardNoteValue(duration * 3 / 8);
4447-
// let scalingFactor=1;
4448-
// if(shortestNoteDenominator>32)
4449-
// scalingFactor=shortestNoteDenominator/32;
4450-
4451-
// if(obj[1]>=scalingFactor)
4452-
// obj[1]=obj[1]/scalingFactor;
4453-
// else
4454-
// obj[0]=obj[0]*scalingFactor;
4455-
4456-
// To get the reduced fraction for 4/2 to 2/1
4457-
obj = this.getClosestStandardNoteValue(obj[0]/obj[1]);
4458-
4459-
// Since we are going to add action block in the front later
4460-
if (k != 0) val = val + 2;
4461-
let pitches = getPitch(val + 5, notes, val);
4462-
currentActionBlock.push(
4463-
[val, ["newnote", {"collapsed": true}], 0, 0, [first ? val-2 : val-1, val+1, val+4, val+pitches.length+5]],
4464-
[val + 1, "divide", 0, 0, [val, val+2, val+3]],
4465-
[val + 2, ["number", { value: obj[0] }], 0, 0, [val + 1]],
4466-
[val + 3, ["number", { value: obj[1] }], 0, 0, [val + 1]],
4467-
[val + 4, "vspace", 0, 0, [val, val + 5]],
4468-
);
4469-
noteblockCount++;
4470-
pitches[0][4][0] = val + 4;
4471-
currentActionBlock = currentActionBlock.concat(pitches);
4472-
4473-
let newLen = jsONON.length + currentActionBlock.length;
4474-
if (k != 0) newLen = newLen + 2;
4475-
currentActionBlock.push(
4476-
[newLen, "hidden", 0, 0, [val, last ? null : newLen + 1]]
4477-
);
4478-
if (isLastNoteInBlock || isLastNoteInSched ) {
4479-
addNewActionBlock(isLastNoteInSched);
4480-
}
4481-
4482-
if (totalnoteblockCount >= MAX_NOTEBLOCKS) {
4483-
this.textMsg("MIDI file is too large.. Generating only 100 noteblocks");
4484-
stopProcessing = true;
4485-
break;
4486-
}
4487-
}
4488-
4489-
if (currentActionBlock.length > 0) {
4490-
addNewActionBlock(true);
4491-
}
4492-
4493-
trackCount++;
4494-
// console.log("current action block: ", currentActionBlock);
4495-
// console.log("current json: ", jsONON);
4496-
// console.log("noteblockCount: ", noteblockCount);
4497-
// console.debug('finished when you see: "block loading finished "');
4498-
document.body.style.cursor = "wait";
4499-
});
4500-
4501-
let len = jsONON.length;
4502-
let m = 0;
4503-
let actionIndex = 0;
4504-
console.log(instruments);
4505-
4506-
for (let i = 0; i < trackCount; i++) {
4507-
let vspaceIndex=len+m+6;
4508-
let startIndex=len+m;
4509-
let flag=true;
4510-
4511-
if (isPercussion[i]) {
4512-
jsONON.push(
4513-
[len + m, ["start", { collapsed: false }], 300 + offset, 100, [null, len + m + 14+actionBlockPerTrack[i], null]],
4514-
[len + m +1,"meter",0,0,[len + m +14 + actionBlockPerTrack[i],len + m +2,len + m +3,len + m + 6]],
4515-
[len + m + 2, ["number",{value: currentMidiTimeSignature[0]}],0,0,[len+m+1]],
4516-
[len + m + 3,"divide",0,0,[len + m +1,len + m + 4,len + m + 5]],
4517-
[len + m + 4,["number", {value : 1}],0,0,[len+m+3]],
4518-
[len + m + 5,["number", {value : currentMidiTimeSignature[1]}],0,0,[len+m+3]],
4519-
[len + m + 6,"vspace",0,0,[len + m + 1,len + m + 8 + actionBlockPerTrack[i]]],
4520-
[len + m + 7, "hidden", 0, 0, [len + m +13 +actionBlockPerTrack[i], len + m + 8]],
4521-
);
4522-
flag = false;
4523-
m+=8;
4524-
} else {
4525-
jsONON.push(
4526-
[len + m, ["start", { collapsed: false }], 300 + offset, 100, [null, len + m+16+actionBlockPerTrack[i], null]],
4527-
[len + m +1,"meter",0,0,[len + m+16+actionBlockPerTrack[i],len + m +2,len + m +3,len + m + 6]],
4528-
[len + m + 2, ["number",{value: currentMidiTimeSignature[0]}],0,0,[len+m+1]],
4529-
[len + m + 3,"divide",0,0,[len + m +1,len + m + 4,len + m + 5]],
4530-
[len + m + 4,["number", {value : 1}],0,0,[len+m+3]],
4531-
[len + m + 5,["number", {value : currentMidiTimeSignature[1]}],0,0,[len+m+3]],
4532-
[len + m + 6,"vspace",0,0,[len + m + 1,len + m + 10 + actionBlockPerTrack[i]]],
4533-
[len + m + 7, "settimbre", 0, 0, [len + m +15 +actionBlockPerTrack[i], len + m + 8, len + m + 10, len + m + 9]],
4534-
[len + m + 8, ["voicename", { value: instruments[i] }], 0, 0, [len + m + 7]],
4535-
[len + m + 9, "hidden", 0, 0, [len + m + 7, null]]
4536-
);
4537-
m += 10;
4538-
}
4539-
4540-
for (let j = 0; j < actionBlockPerTrack[i]; j++) {
4541-
jsONON.push(
4542-
[len + m, ["nameddo", { value: actionBlockNames[actionIndex] }], 0, 0, [flag?len+m-3:len + m - 1, len + m + 1]]
4543-
);
4544-
m++;
4545-
flag=false;
4546-
actionIndex++;
4547-
}
4548-
jsONON[len + m - 1][4][1] = null;
4549-
let setBpmIndex=jsONON.length;
4550-
jsONON.push(
4551-
[setBpmIndex, ["setbpm3"], 0, 0, [vspaceIndex, setBpmIndex + 1, setBpmIndex + 2, setBpmIndex + 5]],
4552-
[setBpmIndex + 1, ["number", { value: currentMidiTempoBpm}], 0, 0, [setBpmIndex]],
4553-
[setBpmIndex + 2, "divide", 0, 0, [setBpmIndex, setBpmIndex + 3, setBpmIndex + 4]],
4554-
[setBpmIndex + 3, ["number", { value: 1 }], 0, 0, [setBpmIndex + 2]],
4555-
[setBpmIndex + 4, ["number", { value: currentMidiTimeSignature[1] }], 0, 0, [setBpmIndex + 2]],
4556-
[setBpmIndex + 5, "vspace", 0, 0, [setBpmIndex, vspaceIndex + 1]],
4557-
);
4558-
m+=6;
4559-
jsONON.push(
4560-
[len + m, "setturtlename2", 0, 0, [startIndex, len + m + 1,startIndex+1]],
4561-
[len + m + 1, ["text", { value: `track${i}` }], 0, 0, [len + m]]
4562-
);
4563-
m+=2;
4564-
4565-
}
4566-
4567-
this.blocks.loadNewBlocks(jsONON);
4568-
// this.textMsg("MIDI import is not currently precise. Consider changing the speed with the Beats Per Minute block or modifying note value with the Multiply Note Value block");
4569-
return null;
4570-
};
4571-
45724231
/**
45734232
* Loads MB project from Planet.
45744233
* @param projectID {Planet project ID}
@@ -6776,7 +6435,7 @@ class Activity {
67766435
const midi = new Midi(e.target.result);
67776436
// eslint-disable-next-line no-console
67786437
console.debug(midi);
6779-
this.transcribeMidi(midi);
6438+
transcribeMidi(midi);
67806439
};
67816440

67826441
const file = that.fileChooser.files[0];
@@ -6876,7 +6535,7 @@ class Activity {
68766535
const midi = new Midi(e.target.result)
68776536
// eslint-disable-next-line no-console
68786537
console.debug(midi);
6879-
this.transcribeMidi(midi);
6538+
transcribeMidi(midi);
68806539
}
68816540

68826541
// Music Block Parser from abc to MB

0 commit comments

Comments
 (0)