/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "mt32emu.h" #include "internals.h" namespace MT32Emu { Poly::Poly() { part = NULL; key = 255; velocity = 255; sustain = false; activePartialCount = 0; for (int i = 0; i < 4; i++) { partials[i] = NULL; } state = POLY_Inactive; next = NULL; } void Poly::setPart(Part *usePart) { part = usePart; } void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain, Partial **newPartials) { if (isActive()) { // This should never happen part->getSynth()->printDebug("Resetting active poly. Active partial count: %i\n", activePartialCount); for (int i = 0; i < 4; i++) { if (partials[i] != NULL && partials[i]->isActive()) { partials[i]->deactivate(); activePartialCount--; } } state = POLY_Inactive; } key = newKey; velocity = newVelocity; sustain = newSustain; activePartialCount = 0; for (int i = 0; i < 4; i++) { partials[i] = newPartials[i]; if (newPartials[i] != NULL) { activePartialCount++; state = POLY_Playing; } } } bool Poly::noteOff(bool pedalHeld) { // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. if (state == POLY_Inactive || state == POLY_Releasing) { return false; } if (pedalHeld) { if (state == POLY_Held) { return false; } state = POLY_Held; } else { startDecay(); } return true; } bool Poly::stopPedalHold() { if (state != POLY_Held) { return false; } return startDecay(); } bool Poly::startDecay() { if (state == POLY_Inactive || state == POLY_Releasing) { return false; } state = POLY_Releasing; for (int t = 0; t < 4; t++) { Partial *partial = partials[t]; if (partial != NULL) { partial->startDecayAll(); } } return true; } bool Poly::startAbort() { if (state == POLY_Inactive || part->getSynth()->isAbortingPoly()) { return false; } for (int t = 0; t < 4; t++) { Partial *partial = partials[t]; if (partial != NULL) { partial->startAbort(); part->getSynth()->abortingPoly = this; } } return true; } void Poly::backupCacheToPartials(PatchCache cache[4]) { for (int partialNum = 0; partialNum < 4; partialNum++) { Partial *partial = partials[partialNum]; if (partial != NULL) { partial->backupCache(cache[partialNum]); } } } /** * Returns the internal key identifier. * For non-rhythm, this is within the range 12 to 108. * For rhythm on MT-32, this is 0 or 1 (special cases) or within the range 24 to 87. * For rhythm on devices with extended PCM sounds (e.g. CM-32L), this is 0, 1 or 24 to 108 */ unsigned int Poly::getKey() const { return key; } unsigned int Poly::getVelocity() const { return velocity; } bool Poly::canSustain() const { return sustain; } PolyState Poly::getState() const { return state; } unsigned int Poly::getActivePartialCount() const { return activePartialCount; } bool Poly::isActive() const { return state != POLY_Inactive; } // This is called by Partial to inform the poly that the Partial has deactivated void Poly::partialDeactivated(Partial *partial) { for (int i = 0; i < 4; i++) { if (partials[i] == partial) { partials[i] = NULL; activePartialCount--; } } if (activePartialCount == 0) { state = POLY_Inactive; if (part->getSynth()->abortingPoly == this) { part->getSynth()->abortingPoly = NULL; } } part->partialDeactivated(this); } Poly *Poly::getNext() const { return next; } void Poly::setNext(Poly *poly) { next = poly; } }