Hi everyone,
I’m trying to automate a process to compose through the use of MIDI files.
The general Idea is just to:
- write something in a DAW
- export a midi file
- Import the file in sc
- uses sc to “compose” all the variations
- Import the new materials in the DAW etc …
A general question, do you know any tool or library in sc or other languages specifically dedicated to MIDI files manipulation like a way to compose music?
I’m trying to do something quite simple, but in the end is not that much …
The main souce is just a single bar of a MIDI file.
I would love to generate new MIDI files based on the first one.
The piece I took like referement is Clapping Music by Steve Reich
Clapping Music - Scrolling Score - YouTube
So the rule is just to shift/rotate the notes.
What I would love it could be something like:
- read the file
- press the magic button
- receive on your desktop all the variations with the “correct” name
- arrange everything in a DAW
For now I’m here but I encountered a problem, if I have a pause/silence at the beginning or at the end of the phrase, happens that those won’t be interpreteted maybe some of you could pointing me out.
// Read the file
~midi = SimpleMIDIFile.read("C:/Users/../Desktop/Bar0.mid");
// how long is it? it considers only the notes and not the rests... if those are at the end..
~totalDurSrc = ~midi.endOfTrack[0][1];
// let me see the events noteNo/noteOff
~events = ~midi.noteEvents;
/* in this example I'm using a rythm in 7/4 at 178 BPM on a single note.
[
[ 0, 0, noteOn, 0, 62, 80 ], [ 0, 96, noteOff, 0, 62, 0 ],
[ 0, 96, noteOn, 0, 62, 80 ], [ 0, 192, noteOff, 0, 62, 0 ],
[ 0, 288, noteOn, 0, 62, 80 ], [ 0, 384, noteOff, 0, 62, 0 ],
[ 0, 480, noteOn, 0, 62, 80 ], [ 0, 576, noteOff, 0, 62, 0 ]
]*/
// reorganize and split
(
~pair = Array.fill((~events.size/2), {arg index;
index = index * 2;
[~events[index], ~events[index+1]];
});
~pairNoteOn = Array.fill((~events.size/2), {arg index;
index = index * 2;
~events[index];
});
~pairNoteOff = Array.fill((~events.size/2), {arg index;
index = index * 2;
~events[index+1];
})
)
; // <<< shifting
// deep copy
~shiftSeq = Array.fill2D(~simpleSeq.size, ~simpleSeq[0].size, {arg row, col;
~simpleSeq[row][col]
});
// shifting
~shiftSeq = ~shiftSeq.rotate(~shift);
// get the first start time
~startTime = ~shiftSeq[0][2];
// time remapping
~shiftSeq.collect({ arg elem, index;
elem[2] = (elem[2] - ~startTime).mod(~totalDurSrc);
})
)
// output -> shift seq -> [[midinote, velocity, start_time, note_duration], etc...]
//5 -> Genera file MIDI
( // init
~newMidiFile = SimpleMIDIFile("C:/Users/../Desktop/Bar0_Variation1.mid");
~newMidiFile.init1(2, 178, "7/4"); // args -> n. tracks, BPM, time signature
~newMidiFile.division = ~midi.division; // adjust the subdivision with the original file, default = 1024 (!important!)
~shiftSeq.do{arg evt;
var midinote = evt[0];
var vel = evt[1];
var start_time = evt[2];
var dur = evt[3];
// noteNumber - velocity - startTime - dur
[midinote, vel, start_time, dur].postln;
~newMidiFile.addNote(midinote, vel, start_time, dur, 0, 0, 1)
};
)
// close the file MIDI
~newMidiFile.adjustEndOfTrack;
// check it
~newMidiFile.midiEvents.dopostln;
// Render MIDI file
~newMidiFile.write
Thank you very much indeed!
I tried another approach using Patterns but I encontered a similar problem as before, I can’t read correctly the .mid the last rest is missed …
b = SimpleMIDIFile.read("C:/Users/../Bar0.mid");
x = b.generatePatternSeqs.flatten(1);//.flatten(1).postln;
x.postcs;
/*
can't read the rest at the end of the phrase
[ [ 62, 1.0 ], [ 62, 1.0 ], [ 'rest', 1.0 ], [ 62, 1.0 ], [ 'rest', 1.0 ], [ 62, 1.0 ] /*????*/ ]
*/
x.rotate(1).debug("rotate: ");
/*
rotate: : [ [ 62, 1.0 ], /*????*/ [ 62, 1.0 ], [ 62, 1.0 ], [ rest, 1.0 ], [ 62, 1.0 ], [ rest, 1.0 ] ]
*/
// create your variation ..
(
p = Pbind(
[\midinote, \dur], Pseq(x.pyramid(1),1),
);
m = SimpleMIDIFile( "~/Desktop/simple_pyramid(1).mid" );
m.init1( 0, 60, "4/4" );
m.fromPattern( p );
)
m.plot;
m.p.play; // note numbers are not rounded
p.play; // compare
m.write; // when writing to file note numbers are rounded (MIDI file format doesn't allow floats)