From e40fc849149dd97c248866a4a1d026dda5e57b62 Mon Sep 17 00:00:00 2001 From: Robert Jonsson Date: Mon, 7 Mar 2011 19:01:11 +0000 Subject: clean3 --- .../synti/zynaddsubfx/Seq/MIDIEvents.C | 85 +++++ .../synti/zynaddsubfx/Seq/MIDIEvents.h | 66 ++++ .../synti/zynaddsubfx/Seq/MIDIFile.C | 389 +++++++++++++++++++++ .../synti/zynaddsubfx/Seq/MIDIFile.h | 90 +++++ .../synti/zynaddsubfx/Seq/Sequencer.C | 165 +++++++++ .../synti/zynaddsubfx/Seq/Sequencer.h | 84 +++++ 6 files changed, 879 insertions(+) create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.C create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.h create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.C create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.h create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.C create mode 100644 attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.h (limited to 'attic/muse_qt4_evolution/synti/zynaddsubfx/Seq') diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.C new file mode 100644 index 00000000..729089c6 --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.C @@ -0,0 +1,85 @@ +/* + ZynAddSubFX - a software synthesizer + + MIDIEvents.C - It stores the midi events from midi file or sequencer + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "MIDIEvents.h" +#include +#include + +MIDIEvents::MIDIEvents(){ +}; + +MIDIEvents::~MIDIEvents(){ +}; + + +/************** Track stuff ***************/ +void MIDIEvents::writeevent(list *l,event *ev){ + listpos *tmp=new listpos; + tmp->next=NULL; + tmp->ev=*ev; + if (l->current!=NULL) l->current->next=tmp; + else l->first=tmp; + l->current=tmp; +// printf("Wx%x ",(int) l->current); +// printf("-> %d \n",l->current->ev.deltatime); + l->size++; +}; + +void MIDIEvents::readevent(list *l,event *ev){ + if (l->current==NULL) { + ev->type=-1; + return; + }; + *ev=l->current->ev; + l->current=l->current->next; + + //test + if (l->current!=NULL) { +// ev->deltatime=10000; +// printf("Rx%d\n",l->current->ev.deltatime); +// printf("Rx%x ",(int) l->current); +// printf("-> %d (next=%x) \n",(int)l->current->ev.deltatime,(int)l->current->next); + }; + +}; + + +void MIDIEvents::rewindlist(list *l){ + l->current=l->first; +}; + +void MIDIEvents::deletelist(list *l){ + l->current=l->first; + if (l->current==NULL) return; + while (l->current->next!=NULL){ + listpos *tmp=l->current; + l->current=l->current->next; + delete(tmp); + }; + deletelistreference(l); +}; + +void MIDIEvents::deletelistreference(list *l){ + l->current=l->first=NULL; + l->size=0; + l->length=0.0; +}; diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.h b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.h new file mode 100644 index 00000000..1bf9befc --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIEvents.h @@ -0,0 +1,66 @@ +/* + ZynAddSubFX - a software synthesizer + + MIDIEvents.h - It stores the midi events from midi file or sequencer + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef MIDI_EVENTS_H +#define MIDI_EVENTS_H + +#include "../globals.h" +#define NUM_MIDI_TRACKS NUM_MIDI_CHANNELS + +class MIDIEvents{ + friend class MIDIFile; + public: + MIDIEvents(); + ~MIDIEvents(); + + protected: + + /* Events */ + struct event{ + int deltatime; + int channel;//on what midi channel is + int type,par1,par2;//type=1 for note, type=2 for controller, type=255 for time messages + } tmpevent; + struct listpos{ + event ev; + struct listpos *next; + }; + struct list{ + listpos *first,*current; + int size;//how many events are + double length;//in seconds + }; + struct { + list track;//the stored track + list record;//the track being "recorded" from midi + } miditrack[NUM_MIDI_TRACKS]; + + void writeevent(list *l,event *ev); + void readevent(list *l,event *ev); + + void rewindlist(list *l); + void deletelist(list *l); + void deletelistreference(list *l); + +}; + + +#endif diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.C new file mode 100644 index 00000000..a5fdaa1c --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.C @@ -0,0 +1,389 @@ +/* + ZynAddSubFX - a software synthesizer + + MIDIFile.C - MIDI file loader + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include +#include "MIDIFile.h" + + +MIDIFile::MIDIFile(){ + midifile=NULL; + midifilesize=0; + midifilek=0; + midieof=false; + me=NULL; +}; + +MIDIFile::~MIDIFile(){ + clearmidifile(); +}; + +int MIDIFile::loadfile(char *filename){ + clearmidifile(); + + FILE *file=fopen(filename,"r"); + if (file==NULL) return(-1); + + char header[4]; + ZERO(header,4); + fread(header,4,1,file); + + //test to see if this a midi file + if ((header[0]!='M')||(header[1]!='T')||(header[2]!='h')||(header[3]!='d')){ + fclose(file); + return(-1); + }; + + //get the filesize + fseek(file,0,SEEK_END); + midifilesize=ftell(file); + rewind(file); + + midifile=new unsigned char[midifilesize]; + ZERO(midifile,midifilesize); + fread(midifile,midifilesize,1,file); + fclose(file); + +// for (int i=0;ime=me_; + + //read the header + int chunk=getint32();//MThd + if (chunk!=0x4d546864) return(-1); + int size=getint32(); + if (size!=6) return(-1);//header is always 6 bytes long + + + int format=getint16(); + printf("format %d\n",format); + + int ntracks=getint16();//this is always 1 if the format is "0" + printf("ntracks %d\n",ntracks); + + int division=getint16(); + printf("division %d\n",division); + if (division>=0){//delta time units in each a quater note +// tick=???; + } else {//SMPTE (frames/second and ticks/frame) + printf("ERROR:in MIDIFile.C::parsemidifile() - SMPTE not implemented yet."); + }; + + if (ntracks>=NUM_MIDI_TRACKS) ntracks=NUM_MIDI_TRACKS-1; + + for (int n=0;nme=NULL; + return(0); +}; + +//private members + + +int MIDIFile::parsetrack(int ntrack){ + printf("\n--==*Reading track %d **==--\n",ntrack); + + int chunk=getint32();//MTrk + if (chunk!=0x4d54726b) return(-1); + + int size=getint32(); + printf("size = %d\n",size); + + int oldmidifilek=midifilek; + + unsigned char lastmsg=0; + unsigned int dt=0; + + while(!midieof){ + unsigned int msgdeltatime=getvarint32(); + +/// printf("MSGDELTATIME = %d\n",msgdeltatime); + +// dt+=msgdeltatime; + + int msg=peekbyte(); +/// printf("raw msg=0x%x ",msg); + if (msg<0x80) { + msg=lastmsg; + } else { + lastmsg=msg; + getbyte(); + }; +/// printf("msg=0x%x\n",msg); + +// dt+=msgdeltatime; + add_dt(ntrack, msgdeltatime); + + unsigned int mtype,mlength; + + switch(msg){ + case 0x80 ... 0x8f://note on off + parsenoteoff(ntrack,msg & 0x0f,dt); + dt=0; + break; + case 0x90 ... 0x9f://note on (or note off) + parsenoteon(ntrack,msg & 0x0f,dt); + dt=0; + break; + case 0xa0 ... 0xaf://aftertouch - ignored + skipnbytes(2); + break; + case 0xb0 ... 0xbf://control change + parsecontrolchange(ntrack,msg & 0x0f,dt); + dt=0; + break; + case 0xc0 ... 0xcf://program change - ignored + skipnbytes(1); + break; + case 0xd0 ... 0xdf://channel pressure - ignored + skipnbytes(1); + break; + case 0xe0 ... 0xef://channel mode messages + skipnbytes(2); + break; + case 0xf0://sysex - ignored + while (getbyte()!=0xf7){ + if (midieof) break; + }; + break; + case 0xf7://sysex (another type) - ignored + skipnbytes(getvarint32()); + break; + + case 0xff://meta-event + mtype=getbyte(); + mlength=getbyte(); + parsemetaevent(mtype,mlength); + break; + + default: + getbyte(); + printf("UNKNOWN message! 0x%x\n",msg); + return(-1); + break; + }; + + + + if (midieof) return(-1); + + if ((midifilek-oldmidifilek)==size) break; + else if((midifilek-oldmidifilek)>size) return(-1); +// if (size!=6) return(-1);//header is always 6 bytes long + }; + + printf("End Track\n\n"); + + return(0); +}; + + +void MIDIFile::parsenoteoff(char ntrack,char chan,unsigned int dt){ + unsigned char note; + note=getbyte(); + + unsigned char noteoff_velocity=getbyte();//unused by zynaddsubfx + noteoff_velocity=0; + if (chan>=NUM_MIDI_CHANNELS) return; + + me->tmpevent.deltatime=convertdt(dt); + me->tmpevent.type=1; + me->tmpevent.par1=note; + me->tmpevent.par2=0; + me->tmpevent.channel=chan; + + printf("Note off:%d \n",note); + + ///test +// ntrack=0; + + me->writeevent(&me->miditrack[(int)ntrack].record,&me->tmpevent); + +}; + + +void MIDIFile::parsenoteon(char ntrack,char chan,unsigned int dt){ + unsigned char note,vel; + note=getbyte(); + vel=getbyte(); + +// printf("ntrack=%d\n",ntrack); + printf("[dt %d ] Note on:%d %d\n",dt,note,vel); + + if (chan>=NUM_MIDI_CHANNELS) return; + + me->tmpevent.deltatime=convertdt(dt); + me->tmpevent.type=1; + me->tmpevent.par1=note; + me->tmpevent.par2=vel; + me->tmpevent.channel=chan; + me->writeevent(&me->miditrack[(int)ntrack].record,&me->tmpevent); + + + +}; + +void MIDIFile::parsecontrolchange(char ntrack,char chan,unsigned int dt){ + unsigned char control,value; + control=getbyte(); + value=getbyte(); + + if (chan>=NUM_MIDI_CHANNELS) return; + + printf("[dt %d] Control change:%d %d\n",dt,control,value); + + me->tmpevent.deltatime=convertdt(dt); + me->tmpevent.type=2; + me->tmpevent.par1=control;//???????????? ma uit la Sequencer::recordnote() din varianele vechi de zyn + me->tmpevent.par2=value; + me->tmpevent.channel=chan; + me->writeevent(&me->miditrack[(int)ntrack].record,&me->tmpevent); + +}; + +void MIDIFile::parsepitchwheel(char ntrack,char chan, unsigned int dt){ + unsigned char valhi,vallo; + vallo=getbyte(); + valhi=getbyte(); + + if (chan>=NUM_MIDI_CHANNELS) return; + + int value=(int)valhi*128+vallo; + + printf("[dt %d] Pitch wheel:%d\n",dt,value); + +}; + +void MIDIFile::parsemetaevent(unsigned char mtype,unsigned char mlength){ + int oldmidifilek=midifilek; + printf("meta-event type=0x%x length=%d\n",mtype,mlength); + + + + midifilek=oldmidifilek+mlength; + +}; + +void MIDIFile::add_dt(char ntrack, unsigned int dt){ + me->tmpevent.deltatime=convertdt(dt); + me->tmpevent.type=255; + me->tmpevent.par1=0; + me->tmpevent.par2=0; + me->tmpevent.channel=0; + me->writeevent(&me->miditrack[(int)ntrack].record,&me->tmpevent); +}; + + +unsigned int MIDIFile::convertdt(unsigned int dt){ + double result=dt; + printf("DT=%d\n",dt); + + return((int) (result*15.0)); +}; + + +void MIDIFile::clearmidifile(){ + if (midifile!=NULL) delete(midifile); + midifile=NULL; + midifilesize=0; + midifilek=0; + midieof=false; + data.tick=0.05; +}; + +unsigned char MIDIFile::getbyte(){ + if (midifilek>=midifilesize) { + midieof=true; + return(0); + }; + +/// printf("(%d) ",midifile[midifilek]); + return(midifile[midifilek++]); +}; + +unsigned char MIDIFile::peekbyte(){ + if (midifilek>=midifilesize) { + midieof=true; + return(0); + }; + return(midifile[midifilek]); +}; + +unsigned int MIDIFile::getint32(){ + unsigned int result=0; + for (int i=0;i<4;i++) { + result=result*256+getbyte(); + }; + if (midieof) result=0; + return(result); +}; + +unsigned short int MIDIFile::getint16(){ + unsigned short int result=0; + for (int i=0;i<2;i++) { + result=result*256+getbyte(); + }; + if (midieof) result=0; + return(result); +}; + +unsigned int MIDIFile::getvarint32(){ + unsigned long result=0; + unsigned char b; + +/// printf("\n[start]"); + + if ((result = getbyte()) & 0x80) { + result &= 0x7f; + do { + b=getbyte(); + result = (result << 7) + (b & 0x7f); + }while (b & 0x80); + } +/// printf("[end - result= %d]\n",result); + return result; +}; + + +void MIDIFile::skipnbytes(int n){ + midifilek+=n; + if (midifilek>=midifilesize){ + midifilek=midifilesize-1; + midieof=true; + }; +}; + diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.h b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.h new file mode 100644 index 00000000..c88f679c --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/MIDIFile.h @@ -0,0 +1,90 @@ +/* + ZynAddSubFX - a software synthesizer + + MIDIFile.h - MIDI file loader + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef MIDIFILE_H +#define MIDIFILE_H + +#include "../globals.h" +#include "MIDIEvents.h" + +class MIDIFile{ + public: + MIDIFile(); + ~MIDIFile(); + + //returns -1 if there is an error, otherwise 0 + int loadfile(char *filename); + + //returns -1 if there is an error, otherwise 0 + int parsemidifile(MIDIEvents *me_); + + private: + MIDIEvents *me; + + unsigned char *midifile; + int midifilesize,midifilek; + bool midieof; + + //returns -1 if there is an error, otherwise 0 + int parsetrack(int ntrack); + + void parsenoteoff(char ntrack,char chan,unsigned int dt); + void parsenoteon(char ntrack,char chan,unsigned int dt); + void parsecontrolchange(char ntrack,char chan,unsigned int dt); + void parsepitchwheel(char ntrack,char chan, unsigned int dt); + void parsemetaevent(unsigned char mtype,unsigned char mlength); + + void add_dt(char ntrack, unsigned int dt); + + void clearmidifile(); + + //convert the delta-time to internal format + unsigned int convertdt(unsigned int dt); + + /* Low Level MIDIfile functions */ + + //get a byte from the midifile + unsigned char getbyte(); + + //peek the current byte from the midifile + unsigned char peekbyte(); + + //get a set of 4 bytes from the midifile + unsigned int getint32(); + + //get a word of 2 bytes from the midifile + unsigned short int getint16(); + + //read a variable length quantity + unsigned int getvarint32(); + + //skip some bytes + void skipnbytes(int n); + + struct { + double tick;//how many seconds one tick has + + }data; + +}; + +#endif diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.C b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.C new file mode 100644 index 00000000..d81ee611 --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.C @@ -0,0 +1,165 @@ +/* + ZynAddSubFX - a software synthesizer + + Sequencer.C - The Sequencer + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include +#include + +#include +#include + +#include "Sequencer.h" + + + +Sequencer::Sequencer(){ + play=0; + for (int i=0;i1sec) sa elimin nota + + if (ntrack==1) printf("_ %f %.2f (%d)\n",nextevent[(int)ntrack].time,playtime[(int)ntrack].abs,nextevent[(int)ntrack].ev.par2); + + *type=nextevent[(int)ntrack].ev.type; + *par1=nextevent[(int)ntrack].ev.par1; + *par2=nextevent[(int)ntrack].ev.par2; + *midich=nextevent[(int)ntrack].ev.channel; + + + double dt=nextevent[(int)ntrack].ev.deltatime*0.0001*realplayspeed; + printf("zzzzzzzzzzzzzz[%d] %d\n",ntrack,nextevent[(int)ntrack].ev.deltatime); + nextevent[(int)ntrack].time+=dt; + +// printf("%f - %d %d \n",nextevent[ntrack].time,par1,par2); + return(0);//?? sau 1 +}; + +/************** Timer stuff ***************/ + +void Sequencer::resettime(timestruct *t){ + t->abs=0.0; + t->rel=0.0; + + timeval tval; + + t->last=0.0; + #ifndef OS_WINDOWS + if (gettimeofday(&tval,NULL)==0) + t->last=tval.tv_sec+tval.tv_usec*0.000001; + #endif + +}; + +void Sequencer::updatecounter(timestruct *t){ + timeval tval; + double current=0.0; + #ifndef OS_WINDOWS + if (gettimeofday(&tval,NULL)==0) + current=tval.tv_sec+tval.tv_usec*0.000001; + #endif + + t->rel=current - t->last; + t->abs+=t->rel; + t->last=current; + +// printf("%f %f %f\n",t->last,t->abs,t->rel); +}; + +void Sequencer::setplayspeed(int speed){ + playspeed=speed; + realplayspeed=pow(10.0,speed/128.0); +}; diff --git a/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.h b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.h new file mode 100644 index 00000000..82ebe495 --- /dev/null +++ b/attic/muse_qt4_evolution/synti/zynaddsubfx/Seq/Sequencer.h @@ -0,0 +1,84 @@ +/* + ZynAddSubFX - a software synthesizer + + Sequencer.h - The Sequencer + Copyright (C) 2003-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SEQUENCER_H +#define SEQUENCER_H + +#include "../globals.h" +#include "MIDIEvents.h" +#include "MIDIFile.h" + +class Sequencer:public MIDIEvents{ + public: + Sequencer(); + ~Sequencer(); + + //theese functions are called by the master and are ignored if the recorder/player are stopped + void recordnote(char chan, char note, char vel); + void recordcontroller(char chan,unsigned int type,int par); + + //this is only for player + //it returns 1 if this must be called at least once more + //it returns 0 if there are no more notes for the current time + //or -1 if there is no note + int getevent(char ntrack, int *midich,int *type,int *par1, int *par2); + + //returns 0 if ok or -1 if there is a error loading file + int importmidifile(char *filename); + + void startplay(); + void stopplay(); + + + int play; + int playspeed;//viteza de rulare (0.1x-10x), 0=1.0x, 128=10x + void setplayspeed(int speed); + + private: + + MIDIFile midifile; + + /* Timer */ + struct timestruct{ + double abs;//the time from the begining of the track + double rel;//the time difference between the last and the current event + double last;//the time of the last event (absolute, since 1 Jan 1970) + //theese must be double, because the float's precision is too low + //and all theese represents the time in seconds + } playtime[NUM_MIDI_TRACKS]; + + void resettime(timestruct *t); + void updatecounter(timestruct *t);//this updates the timer values + + /* Player only*/ + + struct { + event ev; + double time; + } nextevent[NUM_MIDI_TRACKS]; + + double realplayspeed; + +}; + + +#endif + -- cgit v1.2.3