DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/Poly.cpp
00001 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
00002  * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
00003  *
00004  *  This program is free software: you can redistribute it and/or modify
00005  *  it under the terms of the GNU Lesser General Public License as published by
00006  *  the Free Software Foundation, either version 2.1 of the License, or
00007  *  (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 Lesser General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Lesser General Public License
00015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include "mt32emu.h"
00019 #include "PartialManager.h"
00020 
00021 namespace MT32Emu {
00022 
00023 Poly::Poly(Synth *useSynth, Part *usePart) {
00024         synth = useSynth;
00025         part = usePart;
00026         key = 255;
00027         velocity = 255;
00028         sustain = false;
00029         activePartialCount = 0;
00030         for (int i = 0; i < 4; i++) {
00031                 partials[i] = NULL;
00032         }
00033         state = POLY_Inactive;
00034         next = NULL;
00035 }
00036 
00037 void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain, Partial **newPartials) {
00038         if (isActive()) {
00039                 // FIXME: Throw out some big ugly debug output with a lot of exclamation marks - we should never get here
00040                 terminate();
00041         }
00042 
00043         key = newKey;
00044         velocity = newVelocity;
00045         sustain = newSustain;
00046 
00047         activePartialCount = 0;
00048         for (int i = 0; i < 4; i++) {
00049                 partials[i] = newPartials[i];
00050                 if (newPartials[i] != NULL) {
00051                         activePartialCount++;
00052                         state = POLY_Playing;
00053                 }
00054         }
00055 }
00056 
00057 bool Poly::noteOff(bool pedalHeld) {
00058         // Generally, non-sustaining instruments ignore note off. They die away eventually anyway.
00059         // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held.
00060         if (state == POLY_Inactive || state == POLY_Releasing) {
00061                 return false;
00062         }
00063         if (pedalHeld) {
00064                 if (state == POLY_Held) {
00065                         return false;
00066                 }
00067                 state = POLY_Held;
00068         } else {
00069                 startDecay();
00070         }
00071         return true;
00072 }
00073 
00074 bool Poly::stopPedalHold() {
00075         if (state != POLY_Held) {
00076                 return false;
00077         }
00078         return startDecay();
00079 }
00080 
00081 bool Poly::startDecay() {
00082         if (state == POLY_Inactive || state == POLY_Releasing) {
00083                 return false;
00084         }
00085         state = POLY_Releasing;
00086 
00087         for (int t = 0; t < 4; t++) {
00088                 Partial *partial = partials[t];
00089                 if (partial != NULL) {
00090                         partial->startDecayAll();
00091                 }
00092         }
00093         return true;
00094 }
00095 
00096 bool Poly::startAbort() {
00097         if (state == POLY_Inactive) {
00098                 return false;
00099         }
00100         for (int t = 0; t < 4; t++) {
00101                 Partial *partial = partials[t];
00102                 if (partial != NULL) {
00103                         partial->startAbort();
00104                 }
00105         }
00106         return true;
00107 }
00108 
00109 void Poly::terminate() {
00110         if (state == POLY_Inactive) {
00111                 return;
00112         }
00113         for (int t = 0; t < 4; t++) {
00114                 Partial *partial = partials[t];
00115                 if (partial != NULL) {
00116                         partial->deactivate();
00117                 }
00118         }
00119         // FIXME: Throw out lots of debug output - this should never happen
00120         // (Deactivating the partials above should've made them each call partialDeactivated(), ultimately changing the state to POLY_Inactive)
00121         state = POLY_Inactive;
00122 }
00123 
00124 void Poly::backupCacheToPartials(PatchCache cache[4]) {
00125         for (int partialNum = 0; partialNum < 4; partialNum++) {
00126                 Partial *partial = partials[partialNum];
00127                 if (partial != NULL && partial->patchCache == &cache[partialNum]) {
00128                         partial->cachebackup = cache[partialNum];
00129                         partial->patchCache = &partial->cachebackup;
00130                 }
00131         }
00132 }
00133 
00140 unsigned int Poly::getKey() const {
00141         return key;
00142 }
00143 
00144 unsigned int Poly::getVelocity() const {
00145         return velocity;
00146 }
00147 
00148 bool Poly::canSustain() const {
00149         return sustain;
00150 }
00151 
00152 PolyState Poly::getState() const {
00153         return state;
00154 }
00155 
00156 unsigned int Poly::getActivePartialCount() const {
00157         return activePartialCount;
00158 }
00159 
00160 bool Poly::isActive() const {
00161         return state != POLY_Inactive;
00162 }
00163 
00164 // This is called by Partial to inform the poly that the Partial has deactivated
00165 void Poly::partialDeactivated(Partial *partial) {
00166         for (int i = 0; i < 4; i++) {
00167                 if (partials[i] == partial) {
00168                         partials[i] = NULL;
00169                         activePartialCount--;
00170                 }
00171         }
00172         if (activePartialCount == 0) {
00173                 state = POLY_Inactive;
00174         }
00175         part->partialDeactivated(this);
00176 }
00177 
00178 Poly *Poly::getNext() {
00179         return next;
00180 }
00181 
00182 void Poly::setNext(Poly *poly) {
00183         next = poly;
00184 }
00185 
00186 
00187 #ifdef WIN32_DEBUG
00188 void Poly::rawVerifyState( char *name, Synth *useSynth )
00189 {
00190         Poly *ptr1, *ptr2;
00191         Poly poly_temp(synth, part);
00192 
00193 
00194 #ifndef WIN32_DUMP
00195         return;
00196 #endif
00197 
00198         ptr1 = this;
00199         ptr2 = &poly_temp;
00200         useSynth->rawLoadState( name, ptr2, sizeof(*this) );
00201 
00202 
00203         if( ptr1->synth != ptr2->synth ) __asm int 3
00204         if( ptr1->part != ptr2->part ) __asm int 3
00205         if( ptr1->key != ptr2->key ) __asm int 3
00206         if( ptr1->velocity != ptr2->velocity ) __asm int 3
00207         if( ptr1->activePartialCount != ptr2->activePartialCount ) __asm int 3
00208         if( ptr1->sustain != ptr2->sustain ) __asm int 3
00209         if( ptr1->state != ptr2->state ) __asm int 3
00210 
00211         for( int lcv=0; lcv<4; lcv++ ) {
00212                 if( ptr1->partials[lcv] != ptr2->partials[lcv] ) __asm int 3
00213         }
00214 
00215 
00216 
00217         // avoid destructor problems
00218         memset( ptr2, 0, sizeof(*ptr2) );
00219 }
00220 #endif
00221 
00222 
00223 void Poly::saveState( std::ostream &stream )
00224 {
00225         // - static fastptr
00226         //Synth *synth;
00227         //Part *part;
00228 
00229         stream.write(reinterpret_cast<const char*>(&key), sizeof(key) );
00230         stream.write(reinterpret_cast<const char*>(&velocity), sizeof(velocity) );
00231         stream.write(reinterpret_cast<const char*>(&activePartialCount), sizeof(activePartialCount) );
00232         stream.write(reinterpret_cast<const char*>(&sustain), sizeof(sustain) );
00233         stream.write(reinterpret_cast<const char*>(&state), sizeof(state) );
00234 
00235 
00236         // - reloc ptr (!!!)
00237         //Partial *partials[4];
00238         for( int lcv=0; lcv<4; lcv++ ) {
00239                 Bit8u partials_idx;
00240 
00241                 synth->findPartial( partials[lcv], &partials_idx );
00242                 
00243                 stream.write(reinterpret_cast<const char*>(&partials_idx), sizeof(partials_idx) );
00244         }
00245 
00246 
00247 #ifdef WIN32_DEBUG
00248         // DEBUG
00249         synth->rawDumpState( "temp-save", this, sizeof(*this) );
00250         synth->rawDumpNo++;
00251 #endif
00252 }
00253 
00254 
00255 void Poly::loadState( std::istream &stream )
00256 {
00257         // - static fastptr
00258         //Synth *synth;
00259         //Part *part;
00260 
00261         stream.read(reinterpret_cast<char*>(&key), sizeof(key) );
00262         stream.read(reinterpret_cast<char*>(&velocity), sizeof(velocity) );
00263         stream.read(reinterpret_cast<char*>(&activePartialCount), sizeof(activePartialCount) );
00264         stream.read(reinterpret_cast<char*>(&sustain), sizeof(sustain) );
00265         stream.read(reinterpret_cast<char*>(&state), sizeof(state) );
00266 
00267         
00268         // - reloc ptr (!!!)
00269         //Partial *partials[4];
00270         for( int lcv=0; lcv<4; lcv++ ) {
00271                 Bit8u partials_idx;
00272 
00273                 stream.read(reinterpret_cast<char*>(&partials_idx), sizeof(partials_idx) );
00274                 partials[lcv] = (Partial *) synth->indexPartial(partials_idx);
00275         }
00276 
00277 
00278 #ifdef WIN32_DEBUG
00279         // DEBUG
00280         synth->rawDumpState( "temp-load", this, sizeof(*this) );
00281         this->rawVerifyState( "temp-save", synth );
00282         synth->rawDumpNo++;
00283 #endif
00284 }
00285 
00286 }