Skip to content

Commit

Permalink
now keeps the original instruments from songs
Browse files Browse the repository at this point in the history
  • Loading branch information
lvreynoso committed Feb 2, 2019
1 parent b84df46 commit a93325f
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 94 deletions.
Binary file added public/img/spinner.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/scripts/midikov.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ async function generateMIDI(event) {
return;
}
let titlebar = document.getElementById('songTitle')
// console.log(titlebar);
let spinner = new Image(64, 64)
spinner.src = 'img/spinner.gif'
titlebar.appendChild(spinner);
titlebar.textContent = 'Creating song...'
player.pause();
try {
Expand Down
14 changes: 10 additions & 4 deletions source/controllers/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ admin.get('/', (req, res) => {
res.render('admin', { currentUser })
})

admin.post('/upload', upload.array('midis', 64), async (req, res) => {
admin.post('/upload', upload.array('midis', 128), async (req, res) => {
const category = req.body.category;

// update category master list
Expand All @@ -41,10 +41,16 @@ admin.post('/upload', upload.array('midis', 64), async (req, res) => {
newMidi.library = true;
newMidi.category = category;




// pianize the MIDI file
let midiJS = readMIDI(file.buffer);
let pianoVersion = pianize(midiJS);
newMidi.data = Buffer.from(pianoVersion.getContent());
// let midiJS = readMIDI(file.buffer);
// let pianoVersion = pianize(midiJS);
// newMidi.data = Buffer.from(pianoVersion.getContent());

// keep the original instruments
newMidi.data = Buffer.from(file.buffer)

newMidi.save().catch(err => { console.log(err); })
});
Expand Down
27 changes: 10 additions & 17 deletions source/controllers/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import midiFile from 'midifile'
import midiEvents from 'midievents'
import readMIDI from '../lib/read-midi.js'
import writeMIDI from '../lib/write-midi.js'
import transformMIDI from '../lib/transform-midi.js'
import disassembleMIDI from '../lib/disassemble.js'
import generateMIDI from '../lib/generate-midi.js'
import assembleMIDI from '../lib/assemble.js'
import generateMap from '../lib/generate-map.js'
Expand All @@ -32,7 +32,7 @@ generate.post('/', async (req, res) => {
const categoryMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
const midiObjects = categoryMidiDBObjects.map(dbEntry => {
const convertedMidi = readMIDI(dbEntry.data);
const deconstructedMidi = transformMIDI(convertedMidi);
const deconstructedMidi = disassembleMIDI(convertedMidi);
return deconstructedMidi;
});
let failed = false;
Expand All @@ -57,22 +57,15 @@ generate.post('/', async (req, res) => {

} catch (error) {
console.log(error);
failed = true;
} finally {
if (failed) {
res.status(500);
} else {
// send the data
const generatedObject = {
title: `${category} - Generated Order ${order}`,
hex: generatedHex,
path: '/temp/test.midi'
}
const generatedJSON = JSON.stringify(generatedObject);
res.status(200).send(generatedJSON);
}
return res.status(500);
}

const generatedObject = {
title: `${category} Song - Order ${order}`,
hex: generatedHex,
path: '/temp/test.midi'
}
const generatedJSON = JSON.stringify(generatedObject);
res.status(200).send(generatedJSON);
});


Expand Down
23 changes: 13 additions & 10 deletions source/controllers/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import midiFile from 'midifile'
import midiEvents from 'midievents'
import readMIDI from '../lib/read-midi.js'
import writeMIDI from '../lib/write-midi.js'
import transformMIDI from '../lib/transform-midi.js'
import disassembleMIDI from '../lib/disassemble.js'
import generateMIDI from '../lib/generate-midi.js'
import analyzeMIDI from '../lib/analyze.js'
import assembleMIDI from '../lib/assemble.js'
Expand All @@ -29,14 +29,14 @@ test.get('/', (req, res) => {

test.get('/generate', async (req, res) => {
// pull test midis from the data base
const testCategory = 'Pokemon';
const testCategory = 'test';
const query = {
category: testCategory
};
const testMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
const midiObjects = testMidiDBObjects.map(dbEntry => {
const convertedMidi = readMIDI(dbEntry.data);
const deconstructedMidi = transformMIDI(convertedMidi);
const deconstructedMidi = disassembleMIDI(convertedMidi);
return deconstructedMidi;
});
// test with order 1
Expand All @@ -54,14 +54,14 @@ test.get('/generate', async (req, res) => {

test.get('/map', async (req, res) => {
// pull test midis from the data base
const testCategory = 'Pokemon';
const testCategory = 'test';
const query = {
category: testCategory
};
const testMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
const midiObjects = testMidiDBObjects.map(dbEntry => {
const convertedMidi = readMIDI(dbEntry.data);
const deconstructedMidi = transformMIDI(convertedMidi);
const deconstructedMidi = disassembleMIDI(convertedMidi);
return deconstructedMidi;
});
// test with order 1
Expand All @@ -84,7 +84,7 @@ test.get('/assemble', async (req, res) => {
};
const testMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
let testMidi = readMIDI(testMidiDBObjects[0].data);
let testNotes = transformMIDI(testMidi);
let testNotes = disassembleMIDI(testMidi);

let assembledMidi = assembleMIDI(testNotes);

Expand All @@ -108,10 +108,10 @@ test.get('/transform', async (req, res) => {
};
const testMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
let testMidi = readMIDI(testMidiDBObjects[0].data);
let testNotes = transformMIDI(testMidi);
testNotes.forEach(notes => {
// console.log(notes.length);
})
let testNotes = disassembleMIDI(testMidi);
// testNotes.forEach(notes => {
// console.log(notes.length);
// })
// console.log(testNotes);

res.redirect('/test');
Expand All @@ -126,6 +126,9 @@ test.get('/analyze', async (req, res) => {
const testMidiDBObjects = await MIDIFile.find(query).catch(err => { console.log(err) });
let testMidi = readMIDI(testMidiDBObjects[0].data);
let analyzedMIDI = analyzeMIDI(testMidi);
if (analyzedMIDI == true) {
console.log("Success!");
}

res.redirect('/test');
})
Expand Down
31 changes: 11 additions & 20 deletions source/lib/analyze.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ const analyze = (midi) => {
for (let index = 0; index < midi.tracks.length; index++) {
outputMidi.addTrack(index);
let trackEvents = midi.getTrackEvents(index);
let channelMap = {};
let newTrackEvents = trackEvents.map(event => {
// change of instrument events are called "midi program" events.
// they are of event type 0x8 and subtype 0xc.
if (event.type == midiEvents.EVENT_MIDI && event.subtype == midiEvents.EVENT_MIDI_PROGRAM_CHANGE) {
// event.param1 = 0;
// console.log('MIDI Program Change Event');
// console.log(event);
channelMap[event.channel] = event.param1;
console.log(`Channel ${event.channel} switched to instrument ${event.param1}`);
return event;
} else if (event.channel == 0x9) {
// percussion instruments live in event channel 0x9.
Expand All @@ -50,6 +53,7 @@ const analyze = (midi) => {
// console.log(`${note} stopped ${event.delta} clocks after the preceding event.`);
// }
// console.log(event.delta);
// console.log(event);
return event;
} else if (event.type == midiEvents.EVENT_MIDI && event.subtype == midiEvents.EVENT_MIDI_CONTROLLER) {
// synthesizer effects are applied by midi controller events. they are of type 0x8
Expand All @@ -71,8 +75,8 @@ const analyze = (midi) => {
// the tempo parameter is the number of microseconds per quarter note.
// Divide 60,000,000 / this parameter and you get the bpm of the song.
// TRACK 0
console.log(`SET TEMPO event on Track ${index}`);
console.log(event);
// console.log(`SET TEMPO event on Track ${index}`);
// console.log(event);
return event;
} else if (event.type == midiEvents.EVENT_META && event.subtype == midiEvents.EVENT_META_MARKER) {
// this midi 'meta' marker event is simply a marker - it does the same function
Expand All @@ -90,8 +94,8 @@ const analyze = (midi) => {
// 4: number of notated 32nd notes in a MIDI quarter-note. usually 8.
// type: 0xff, subtype: 0x58
// TRACK 0
console.log(`Set time signature on Track ${index}`);
console.log(event);
// console.log(`Set time signature on Track ${index}`);
// console.log(event);
return event;
} else if (event.type == midiEvents.EVENT_META && event.subtype == midiEvents.EVENT_META_KEY_SIGNATURE) {
// this event has two properties: key and scale. the key property specifies
Expand All @@ -100,8 +104,8 @@ const analyze = (midi) => {
// the scale property is 0 for a major key, and 1 for a minor key.
// type: 0xff, subtype: 0x59
// TRACK 0
console.log(`Set key signature on Track ${index}`);
console.log(event);
// console.log(`Set key signature on Track ${index}`);
// console.log(event);
return event;
} else if (event.type == midiEvents.EVENT_MIDI && event.subtype == midiEvents.EVENT_MIDI_PITCH_BEND) {
// fancy pitch bending. type 0x08, subtype 0xe.
Expand All @@ -128,22 +132,9 @@ const analyze = (midi) => {
return event;
}
});
// let filteredTrackEvents = newTrackEvents.filter(element => {
// if (element == 99) {
// return false
// } else {
// return true
// }
// })
console.log(`Track ${index} has ${newTrackEvents.length} events.`);
// if (index == 0 || index == 4 || index == 5) {
// filteredTrackEvents.forEach(element => {
// console.log(element);
// })
// }
outputMidi.setTrackEvents(index, newTrackEvents);
}
return outputMidi;
return true;
}

export default analyze;
47 changes: 30 additions & 17 deletions source/lib/assemble.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const assemble = (midiData) => {
outputMidi.addTrack(trackIndex);
let trackNotes = midiData.trackNotes[trackIndex];
// gets the wrong channel for some reason
let trackChannel = parseInt(trackIndex, 16);
let trackChannel = parseInt(trackIndex, 10);
// console.log(`Instrument Channel: ${trackChannel}`);
// all track events
let trackEvents = [];
Expand All @@ -106,6 +106,16 @@ const assemble = (midiData) => {
// key: 0x00,
// scale: 0x00
// }

if (trackKeySignature != undefined) {
trackEvents.push(trackKeySignature);
}
// trackEvents.push(trackProgram);

// convert each 'Note' to a pair of MIDI events: note on and note off.
// if the note's instrument does not match the current program,
// then change programs with a new event.

// Program Change (Set the instrument)
let trackProgram = {
delta: 0x00,
Expand All @@ -114,12 +124,6 @@ const assemble = (midiData) => {
channel: trackChannel,
param1: 0x00
}
if (trackKeySignature != undefined) {
trackEvents.push(trackKeySignature);
}
trackEvents.push(trackProgram);

// convert each 'Note' to a pair of MIDI events: note on and note off.

let noteOnTemplate = {
delta: 0x00,
Expand All @@ -143,18 +147,26 @@ const assemble = (midiData) => {
// create all the events at the proper 'tick'
// THEN go through the hashmap and assemble events
// calculate deltas by the distance between ticks
// apparently Javascript has problems with hexadecimal math
// apparently Javascript doesn't distinguish well between hex and decimals
// so ticks are in decimal numbers. seems to work...
let noteTracker = {};
let ticks = 0;
let currentInstrument = 0x00;
trackNotes.forEach(note => {
// if (note.alpha > 0x300) {
// note.alpha = 0x300;
// }
// if (note.duration > 0x300) {
// note.duration = 0x300;
// }
ticks += note.alpha;

// check the instrument
if (note.instrument != currentInstrument) {
let programChange = Object.assign({}, trackProgram);
programChange.param1 = note.instrument;
if (noteTracker[ticks] == undefined) {
noteTracker[ticks] = [programChange];
} else {
noteTracker[ticks].push(programChange);
}
currentInstrument = note.instrument;
}

// add the on event
let noteOn = Object.assign({}, noteOnTemplate);
noteOn.channel = trackChannel;
Expand Down Expand Up @@ -187,9 +199,10 @@ const assemble = (midiData) => {
let currentTime = parseInt(time, 10);
noteTracker[time].forEach(event => {
event.delta = currentTime - previousTick;
// if (event.delta > 0x300) {
// console.log(event);
// }
// for the weird stuff
if (event.delta < 0) {
console.log(event);
}
trackEvents.push(event);
previousTick = currentTime;
})
Expand Down
Loading

0 comments on commit a93325f

Please sign in to comment.