bool ANIObject::drawANI(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { if (!hasBuffer()) { uint16 width, height; _ani->getMaxSize(width, height); resizeBuffer(width, height); } const ANIFile::Animation &animation = _ani->getAnimationInfo(_animation); if (_frame >= animation.frameCount) return false; const ANIFile::FrameArea &area = animation.frameAreas[_frame]; left = _x + area.left; top = _y + area.top; right = _x + area.right; bottom = _y + area.bottom; if (!saveScreen(dest, left, top, right, bottom)) return false; _ani->draw(dest, _animation, _frame, _x, _y); return true; }
bool ANIObject::drawCMP(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) { if (!hasBuffer()) { uint16 width, height; _cmp->getMaxSize(width, height); resizeBuffer(width, height); } left = _x; top = _y; right = _x + _cmp->getWidth (_animation) - 1; bottom = _y + _cmp->getHeight(_animation) - 1; if (!saveScreen(dest, left, top, right, bottom)) return false; _cmp->draw(dest, _animation, _x, _y, 0); return true; }
void BaseAudioEvent::mixBuffer( AudioBuffer* outputBuffer, int bufferPosition, int minBufferPosition, int maxBufferPosition, bool loopStarted, int loopOffset, bool useChannelRange ) { if ( !hasBuffer() ) return; lock(); // prevents buffer mutations (from outside threads) during this read cycle int bufferSize = outputBuffer->bufferSize; // if the output channel amount differs from this events channel amount, we might // potentially have a bad time (e.g. engine has mono output while this event is stereo) // ideally events should never hold more channels than AudioEngineProps::OUTPUT_CHANNELS int outputChannels = std::min( _buffer->amountOfChannels, outputBuffer->amountOfChannels ); int readPointer, i, c, ca; SAMPLE_TYPE* srcBuffer; SAMPLE_TYPE* tgtBuffer; // non-loopeable event whose playback is tied to the Sequencer if ( !_loopeable ) { for ( i = 0; i < bufferSize; ++i ) { readPointer = i + bufferPosition; // over the max position ? read from the start ( implies that sequence has started loop ) if ( readPointer > maxBufferPosition ) { if ( useChannelRange ) // TODO: channels use a min buffer position too ? (currently drummachine only) readPointer -= maxBufferPosition; else if ( !loopStarted ) break; } if ( readPointer >= _sampleStart && readPointer <= _sampleEnd ) { // mind the offset ! ( cached buffer starts at 0 while // the _sampleStart defines where the event is positioned in the sequencer ) readPointer -= _sampleStart; for ( c = 0; c < outputChannels; ++c ) { srcBuffer = _buffer->getBufferForChannel( c ); tgtBuffer = outputBuffer->getBufferForChannel( c ); tgtBuffer[ i ] += ( srcBuffer[ readPointer ] * _volume ); } } else if ( loopStarted && i >= loopOffset ) { readPointer = minBufferPosition + ( i - loopOffset ); if ( readPointer >= _sampleStart && readPointer <= _sampleEnd ) { readPointer -= _sampleStart; for ( c = 0, ca = _buffer->amountOfChannels; c < ca; ++c ) { srcBuffer = _buffer->getBufferForChannel( c ); tgtBuffer = outputBuffer->getBufferForChannel( c ); tgtBuffer[ i ] += ( srcBuffer[ readPointer ] * _volume ); } } } } } else { // loopeable events mix their buffer contents using an internal read pointer bool monoCopy = _buffer->amountOfChannels < outputBuffer->amountOfChannels; int maxBufPos = _buffer->bufferSize - 1; int writePointer = 0; readPointer = _readPointer; // use internal read pointer when reading loopeable content for ( i = 0; i < bufferSize; ++i, ++writePointer ) { readPointer = i + bufferPosition; // read sample when the read pointer is within sample start and end points if ( readPointer >= _sampleStart && readPointer <= _sampleEnd ) { // use range pointers to read within the specific sample ranges for ( c = 0, ca = _buffer->amountOfChannels; c < ca; ++c ) { // this sample might have less channels than the output buffer if ( !monoCopy ) srcBuffer = _buffer->getBufferForChannel( c ); else srcBuffer = _buffer->getBufferForChannel( 0 ); tgtBuffer = outputBuffer->getBufferForChannel( c ); tgtBuffer[ writePointer ] += ( srcBuffer[ _readPointer ] * _volume ); } // this is a loopeable sample (thus using internal read pointer) // set the internal read pointer to the sample start so it keeps playing indefinitely if ( ++_readPointer > maxBufPos ) _readPointer = 0; } else if ( loopStarted && readPointer > maxBufferPosition ) { // in case the Sequencers read offset exceeds the maximum and the // Sequencer is looping, read from start. internal _readPointer takes care of correct offset bufferPosition -= loopOffset; // decrement iterators as no write occurred in this iteration --i; --writePointer; } } } unlock(); // release lock }