00001 /* 00002 Copyright (C) 2003 The Pentagram Team 00003 00004 This program is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU General Public License 00006 as published by the Free Software Foundation; either version 2 00007 of the License, or (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 // Tab Size = 4 00020 00021 #ifndef XMIDINOTESTACK_H_INCLUDED 00022 #define XMIDINOTESTACK_H_INCLUDED 00023 00024 #include "XMidiEvent.h" 00025 00026 class XMidiNoteStack { 00027 XMidiEvent *notes; // Top of the stack 00028 int polyphony; 00029 int max_polyphony; 00030 public: 00031 00032 XMidiNoteStack() : notes(0), polyphony(0), max_polyphony(0) { } 00033 00034 // Just clear it. Don't care about what's actually in it 00035 inline void clear() { 00036 notes=0; 00037 polyphony=0; 00038 max_polyphony=0; 00039 } 00040 00041 // Pops the top of the stack if its off_time is <= time (6000th of second) 00042 inline XMidiEvent *PopTime(uint32 time) { 00043 if (notes && notes->ex.note_on.note_time <= time) { 00044 XMidiEvent *note = notes; 00045 notes = note->ex.note_on.next_note; 00046 note->ex.note_on.next_note = 0; 00047 polyphony--; 00048 return note; 00049 } 00050 00051 return 0; 00052 } 00053 00054 // Pops the top of the stack 00055 inline XMidiEvent *Pop() { 00056 if (notes) { 00057 XMidiEvent *note = notes; 00058 notes = note->ex.note_on.next_note; 00059 note->ex.note_on.next_note = 0; 00060 polyphony--; 00061 return note; 00062 } 00063 00064 return 0; 00065 } 00066 00067 // Pops the top of the stack 00068 inline XMidiEvent *Remove(XMidiEvent *event) { 00069 XMidiEvent *prev = 0; 00070 XMidiEvent *note = notes; 00071 while (note) { 00072 00073 if (note == event) { 00074 if (prev) prev->ex.note_on.next_note = note->ex.note_on.next_note; 00075 else notes = note->ex.note_on.next_note; 00076 note->ex.note_on.next_note = 0; 00077 polyphony--; 00078 return note; 00079 } 00080 prev = note; 00081 note = note->ex.note_on.next_note; 00082 } 00083 return 0; 00084 } 00085 00086 // Finds the note that has same pitch and channel, and pops it 00087 inline XMidiEvent *FindAndPop(XMidiEvent *event) { 00088 00089 XMidiEvent *prev = 0; 00090 XMidiEvent *note = notes; 00091 while (note) { 00092 00093 if ((note->status & 0xF) == (event->status & 0xF) && note->data[0] == event->data[0]) { 00094 if (prev) prev->ex.note_on.next_note = note->ex.note_on.next_note; 00095 else notes = note->ex.note_on.next_note; 00096 note->ex.note_on.next_note = 0; 00097 polyphony--; 00098 return note; 00099 } 00100 prev = note; 00101 note = note->ex.note_on.next_note; 00102 } 00103 return 0; 00104 } 00105 00106 // Pushes a note onto the top of the stack 00107 inline void Push(XMidiEvent *event) { 00108 event->ex.note_on.next_note = notes; 00109 notes = event; 00110 polyphony++; 00111 if (max_polyphony < polyphony) max_polyphony = polyphony; 00112 } 00113 00114 inline void Push(XMidiEvent *event, uint32 time) { 00115 event->ex.note_on.note_time = time; 00116 event->ex.note_on.next_note = 0; 00117 00118 polyphony++; 00119 if (max_polyphony < polyphony) max_polyphony = polyphony; 00120 00121 if (!notes || time <= notes->ex.note_on.note_time) { 00122 event->ex.note_on.next_note = notes; 00123 notes = event; 00124 } 00125 else { 00126 XMidiEvent *prev = notes; 00127 while (prev) { 00128 XMidiEvent *note = prev->ex.note_on.next_note; 00129 00130 if (!note || time <= note->ex.note_on.note_time) { 00131 event->ex.note_on.next_note = note; 00132 prev->ex.note_on.next_note = event; 00133 return; 00134 } 00135 prev = note; 00136 } 00137 } 00138 } 00139 00140 // Finds the note that has same pitch and channel, and sets its after touch to our velocity 00141 inline void SetAftertouch(XMidiEvent *event) { 00142 00143 XMidiEvent *prev = 0; 00144 XMidiEvent *note = notes; 00145 while (note) { 00146 00147 if ((note->status & 0xF) == (event->status & 0xF) && note->data[0] == event->data[0]) { 00148 note->ex.note_on.actualvel = event->data[1]; 00149 return; 00150 } 00151 prev = note; 00152 note = note->ex.note_on.next_note; 00153 } 00154 } 00155 00156 inline XMidiEvent* GetNotes() { 00157 return notes; 00158 } 00159 00160 inline int GetPolyphony() { 00161 return polyphony; 00162 } 00163 00164 inline int GetMaxPolyphony() { 00165 return max_polyphony; 00166 } 00167 }; 00168 00169 #endif //XMIDINOTESTACK_H_INCLUDED