summaryrefslogtreecommitdiff
path: root/vfg/src/music.cpp
diff options
context:
space:
mode:
authorTim Redfern <tim@gray.(none)>2012-11-01 21:10:31 +0000
committerTim Redfern <tim@gray.(none)>2012-11-01 21:10:31 +0000
commitc31a609399c2e05a50a5df8be10049903521c9e7 (patch)
tree246c2c9a67ad0fc8b7473006d0763ab8bbf22675 /vfg/src/music.cpp
initial commit
Diffstat (limited to 'vfg/src/music.cpp')
-rwxr-xr-xvfg/src/music.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/vfg/src/music.cpp b/vfg/src/music.cpp
new file mode 100755
index 0000000..82e953e
--- /dev/null
+++ b/vfg/src/music.cpp
@@ -0,0 +1,91 @@
+#include "music.h"
+
+//event times & durations are absolute integer milliseconds
+
+note::note(int n,int v,int d){
+ num=n;
+ velocity=v;
+ duration=d;
+}
+void musicscore::parseMidi(string filename){
+ // millis = 60000 / (BPM * PPQ)
+ // BPM = 60000000 / MQPN (last 3 bytes of midi tempoSet)
+ // http://www.lastrayofhope.com/2009/12/23/midi-delta-time-ticks-to-seconds/
+ // presume no change in time signature?
+
+ //2 passes:: extract notes & set abs times, then scan for
+
+ float wt=ofGetElapsedTimef();
+
+ float BPM=120.0f;
+ //input:: MPQN :: default 500000
+ float MPQN=60000000.0f/BPM;
+ //unknown:: ticks per quarter note
+ int TPQN=96;
+ //want:: seconds per tick in float
+ float SPT =(MPQN/1000000.0f)/TPQN;
+
+ float time=0; //counts up in float seconds but converts to millis for map index
+
+ map<int,note*> events;
+
+ if( !XML.loadFile(filename) ){
+ printf("unable to load %s check data/ folder\n",filename.c_str());
+ }else{
+ if(XML.pushTag("MidiFile")) {
+ for (int i=0;i<XML.getNumTags("TrackChunk");i++) {
+ XML.pushTag("TrackChunk",i);
+ for (int i=0;i<XML.getNumTags("Event");i++) {
+ time+=(SPT*XML.getAttribute("Event", "DeltaTimeTicks",0,i));
+ if (XML.getAttribute("Event", "Label","",i)=="TempoSet") {
+ string data=XML.getAttribute("Event", "Data","",i);
+ char* endptr;
+ int d1=strtoul(data.substr(6,2).c_str(),&endptr,16);
+ int d2=strtoul(data.substr(9,2).c_str(),&endptr,16);
+ int d3=strtoul(data.substr(12,2).c_str(),&endptr,16);
+ int MPQN=(d1<<16)+(d2<<8)+d3;
+ SPT =(MPQN/1000000.0f)/TPQN;
+ //printf("Tempo change: seconds per tick now: %f\n",SPT);
+ }
+ if (XML.getAttribute("Event", "Label","",i)=="NoteOn"||XML.getAttribute("Event", "Label","",i)=="NoteOff") {
+ string data=XML.getAttribute("Event", "Data","",i);
+ char* endptr;
+ int d1=strtoul(data.substr(0,2).c_str(),&endptr,16);
+ int d2=strtoul(data.substr(3,2).c_str(),&endptr,16);
+ int id=strtoul(XML.getAttribute("Event", "Id","",i).c_str(),&endptr,16);
+ if (id==128||id==144) events[(int)(time*1000.0f)]=new note(d1,d2,id); //noteon/off
+ }
+ }
+ XML.popTag();
+ }
+
+ }
+ XML.popTag();
+ }
+ //iterate events and compute durations now the absolute times are established: extract to notes
+ map<int,note*>::iterator iter1;
+ map<int,note*>::iterator iter2;
+
+ for (iter1 = events.begin(); iter1 != events.end(); ++iter1) {
+ if (iter1->second->duration==144) {
+ iter1->second->duration=0;
+ iter2=iter1;
+ while (++iter2 != events.end()) {
+ if ((iter1->second->num==iter2->second->num)&&(iter2->second->duration==128)) {
+ iter1->second->duration=iter2->first-iter1->first;
+ notes[iter1->first]=iter1->second;
+ //printf("%i: noteon %i %i\n",iter1->first,iter1->second->num,iter1->second->duration);
+ break;
+ }
+ }
+ }
+ }
+ printf("processed %s: %i notes in %f seconds\n",filename.c_str(),notes.size(),ofGetElapsedTimef()-wt);
+}
+
+song::song(string backfile,string melfile,string notefile) {
+ backing.loadSound(backfile);
+ melody.loadSound(melfile);
+ notes.parseMidi(notefile);
+ bpm=bpm; //can be used to set tempo eventually? keeps everything simple to do it this way
+}