예제 #1
0
    /**
     * used by the cacheAudioEventsForMeasure-method, this collects
     * all AudioEvents in the requested measure for entry into the BulkCacher
     *
     * @param bufferPosition {int} the desired measures buffers start pointer
     * @param bufferEnd      {int} the desired measures buffers end pointer
     *
     * @return {std::vector<BaseCacheableAudioEvent*>}
     */
    std::vector<BaseCacheableAudioEvent*>* collectCacheableSequencerEvents( int bufferPosition, int bufferEnd )
    {
        std::vector<BaseCacheableAudioEvent*>* events = new std::vector<BaseCacheableAudioEvent*>();

        for ( int i = 0, l = instruments.size(); i < l; ++i )
        {
            std::vector<BaseAudioEvent*>* audioEvents = instruments.at( i )->getEvents();
            int amount = audioEvents->size();

            for ( int j = 0; j < amount; j++ )
            {
                BaseAudioEvent* audioEvent = audioEvents->at( j );

                // if event is an instance of BaseCacheableAudioEvent add it to the list
                if ( dynamic_cast<BaseCacheableAudioEvent*>( audioEvent ) != NULL )
                {
                    int sampleStart = audioEvent->getSampleStart();
                    int sampleEnd   = audioEvent->getSampleEnd();

                    if (( sampleStart >= bufferPosition && sampleStart <= bufferEnd ) ||
                        ( sampleStart <  bufferPosition && sampleEnd >= bufferPosition ))
                    {
                        if ( !audioEvent->isDeletable())
                            events->push_back(( BaseCacheableAudioEvent* ) audioEvent );
                    }
                }
            }
        }
        return events;
    }
예제 #2
0
TEST( BaseAudioEvent, PositionInSamples )
{
    BaseAudioEvent* audioEvent = new BaseAudioEvent();

    int sampleLength = randomInt( 512, 8192 );
    int sampleStart  = randomInt( 0, sampleLength / 2 );
    int expectedEnd  = sampleStart + ( sampleLength - 1 );

    audioEvent->setSampleStart ( sampleStart );
    audioEvent->setSampleLength( sampleLength );

    EXPECT_EQ( sampleStart,  audioEvent->getSampleStart() );
    EXPECT_EQ( expectedEnd,  audioEvent->getSampleEnd() );
    EXPECT_EQ( sampleLength, audioEvent->getSampleLength() );

    // test whether values in seconds have updated accordingly

    int SAMPLE_RATE = 44100;
    float expectedStartPosition = BufferUtility::bufferToSeconds( sampleStart, SAMPLE_RATE );
    float expectedEndPosition   = BufferUtility::bufferToSeconds( expectedEnd, SAMPLE_RATE );
    float expectedDuration      = expectedEndPosition - expectedStartPosition;

    EXPECT_FLOAT_EQ( expectedStartPosition, audioEvent->getStartPosition() );
    EXPECT_FLOAT_EQ( expectedEndPosition,   audioEvent->getEndPosition() );
    EXPECT_FLOAT_EQ( expectedDuration,      audioEvent->getDuration() );

    // test auto sanitation of properties

    audioEvent->setSampleEnd( expectedEnd * 2 );
    EXPECT_EQ( expectedEnd, audioEvent->getSampleEnd() )
        << "expected sample end not to exceed the range set by the sample start and length properties";

    sampleLength /= 2;
    audioEvent->setSampleLength( sampleLength );
    expectedEnd = sampleStart + ( sampleLength - 1 );

    EXPECT_EQ( expectedEnd, audioEvent->getSampleEnd() )
        << "expected sample end not to exceed the range set by the sample start and updated length properties";

    // test non sanitation of properties for loopeable events

    audioEvent->setLoopeable( true );

    expectedEnd *= 2;
    audioEvent->setSampleEnd( expectedEnd );

    EXPECT_EQ( expectedEnd, audioEvent->getSampleEnd() )
        << "expected sample end to exceed the range set by the sample start and length properties for loopeable event";

    sampleLength /= 2;
    audioEvent->setSampleLength( sampleLength );

    EXPECT_EQ( expectedEnd, audioEvent->getSampleEnd() )
        << "expected sample end to exceed the range set by the sample start and updated length properties for loopeable event";

    deleteAudioEvent( audioEvent );
}
예제 #3
0
    /**
     * used by the getAudioEvents-method of the sequencer, this validates
     * the present AudioEvents against the requested position
     * and updates and flushes the removal queue
     *
     * @param instrument     {BaseInstrument*} instrument to gather events from
     * @param bufferPosition {int} the current buffers start pointer
     * @param bufferEnd      {int} the current buffers end pointer
     */
    void collectSequencedEvents( BaseInstrument* instrument, int bufferPosition, int bufferEnd )
    {
        if ( !instrument->hasEvents() )
            return;

        AudioChannel* channel                     = instrument->audioChannel;
        std::vector<BaseAudioEvent*>* audioEvents = instrument->getEvents();

        // removal queue
        std::vector<BaseAudioEvent*> removes;

        // channel has an internal loop (e.g. drum machine) ? recalculate requested
        // buffer position by subtracting all measures above the first
        if ( channel->maxBufferPosition > 0 )
        {
            int samplesPerBar = AudioEngine::samples_per_bar;

            while ( bufferPosition >= channel->maxBufferPosition )
            {
                bufferPosition -= samplesPerBar;
                bufferEnd      -= samplesPerBar;
            }
        }
        int i = 0, amount = audioEvents->size();
        for ( i; i < amount; i++ )
        {
            BaseAudioEvent* audioEvent = audioEvents->at( i );

            if ( audioEvent->isEnabled() )
            {
                int sampleStart = audioEvent->getSampleStart();
                int sampleEnd   = audioEvent->getSampleEnd();

                if ( audioEvent->isLoopeable() ||
                   ( sampleStart >= bufferPosition && sampleStart <= bufferEnd ) ||
                   ( sampleStart <  bufferPosition && sampleEnd >= bufferPosition ))
                {
                    if ( !audioEvent->isDeletable())
                        channel->addEvent( audioEvent );
                    else
                        removes.push_back( audioEvent );
                }
            }
        }
        // removal queue filled ? process it so we can safely
        // remove "deleted" AudioEvents without errors occurring
        if ( removes.size() > 0 )
        {
            int i = 0;
            for ( i; i < removes.size(); i++ )
            {
                BaseAudioEvent* audioEvent = removes[ i ];
                instrument->removeEvent( audioEvent, false );
            }
        }
    }
예제 #4
0
TEST( BaseAudioEvent, MixBufferLoopeableEvent )
{
    BaseAudioEvent* audioEvent = new BaseAudioEvent();

    int sourceSize            = 16;
    AudioBuffer* sourceBuffer = new AudioBuffer( 1, sourceSize );
    SAMPLE_TYPE* rawBuffer    = sourceBuffer->getBufferForChannel( 0 );
    fillAudioBuffer( sourceBuffer );

    audioEvent->setBuffer( sourceBuffer, false );
    audioEvent->setLoopeable( true );
    audioEvent->setSampleLength( 16 * 4 ); // thus will loop 4 times
    audioEvent->positionEvent ( 0, 16, 0 );

    // create an output buffer at a size smaller than the source buffer length

    int outputSize = ( int )(( double ) sourceSize * .4 );
    AudioBuffer* targetBuffer = new AudioBuffer( sourceBuffer->amountOfChannels, outputSize );

    int minBufferPos = audioEvent->getSampleStart();
    int bufferPos    = minBufferPos;
    int maxBufferPos = audioEvent->getSampleEnd();

    // test the seamless mixing over multiple iterations

    for ( ; bufferPos < maxBufferPos; bufferPos += outputSize )
    {
        // mix buffer contents

        targetBuffer->silenceBuffers();
        bool loopStarted = bufferPos + ( outputSize - 1 ) > maxBufferPos;
        int loopOffset   = ( maxBufferPos - bufferPos ) + 1;
        audioEvent->mixBuffer( targetBuffer, bufferPos, minBufferPos, maxBufferPos, loopStarted, loopOffset, false );

        // assert results

        SAMPLE_TYPE* mixedBuffer = targetBuffer->getBufferForChannel( 0 );

        for ( int i = 0; i < outputSize; ++i )
        {
            int compareOffset = ( bufferPos + i ) % sourceSize;

            EXPECT_EQ( rawBuffer[ compareOffset ], mixedBuffer[ i ] )
                << "expected mixed buffer contents to equal the source contents at mixed offset " << i << " for source offset " << compareOffset;
        }
    }

    delete targetBuffer;
    delete sourceBuffer;
    delete audioEvent;
}
예제 #5
0
TEST( BaseAudioEvent, PositionInSeconds )
{
    BaseAudioEvent* audioEvent = new BaseAudioEvent();

    float startPosition = randomFloat( 0, 10 );
    float endPosition   = startPosition + randomFloat( 0, 10 );

    int SAMPLE_RATE = 44100;

    float expectedDuration   = endPosition - startPosition;
    int expectedSampleStart  = BufferUtility::secondsToBuffer( startPosition, SAMPLE_RATE );
    int expectedSampleEnd    = BufferUtility::secondsToBuffer( endPosition, SAMPLE_RATE );
    int expectedSampleLength = ( expectedSampleEnd - expectedSampleStart ) - 1;
    audioEvent->setStartPosition( startPosition );

    EXPECT_FLOAT_EQ( startPosition, audioEvent->getStartPosition() );
    EXPECT_FLOAT_EQ( startPosition, audioEvent->getEndPosition() )
        << "expected end position to equal start position (hasn't been explicitly set yet)";
    EXPECT_FLOAT_EQ( 0, audioEvent->getDuration())
        << "expected zero duration (duration nor end haven't been explicitly set yet)";
    EXPECT_EQ( 0, audioEvent->getSampleLength())
        << "expected zero sample length (duration nor end haven't been explicitly set yet)";
    EXPECT_EQ( expectedSampleStart, audioEvent->getSampleStart() )
        << "expected sample start to have been updated after setting start position";

    audioEvent->setEndPosition( endPosition );

    EXPECT_FLOAT_EQ( startPosition, audioEvent->getStartPosition() );
    EXPECT_FLOAT_EQ( endPosition, audioEvent->getEndPosition() );
    EXPECT_FLOAT_EQ( expectedDuration, audioEvent->getDuration() );
    EXPECT_EQ( expectedSampleEnd, audioEvent->getSampleEnd())
        << "expected sample end to have been updated after setting end position";
    EXPECT_EQ( expectedSampleLength, audioEvent->getSampleLength())
        << "expected sample length to have been updated after setting end position";

    expectedDuration /= 2;
    float expectedEndPosition = startPosition + expectedDuration;
    audioEvent->setDuration( expectedDuration );

    EXPECT_FLOAT_EQ( expectedDuration, audioEvent->getDuration() );
    EXPECT_FLOAT_EQ( expectedEndPosition, audioEvent->getEndPosition())
        << "expected end position to have corrected after updating of duration";

    deleteAudioEvent( audioEvent );
}
예제 #6
0
TEST( BaseAudioEvent, PositionEvent )
{
    BaseAudioEvent* audioEvent   = new BaseAudioEvent();
    AudioEngine::samples_per_bar = randomInt( 11025, 88200 );

    int sampleLength = randomInt( 24, 8192 );
    audioEvent->setSampleLength( sampleLength );

    int startMeasure = randomInt( 0, 15 );
    int subdivisions = randomInt( 4, 128 );
    int offset       = randomInt( 0, 64 );

    audioEvent->positionEvent( startMeasure, subdivisions, offset );

    int expectedSampleStart = ( startMeasure * AudioEngine::samples_per_bar ) +
                              ( offset * AudioEngine::samples_per_bar / subdivisions );
    int expectedSampleEnd   = expectedSampleStart + sampleLength - 1;

    EXPECT_EQ( expectedSampleStart, audioEvent->getSampleStart() );
    EXPECT_EQ( expectedSampleEnd,   audioEvent->getSampleEnd() );

    deleteAudioEvent( audioEvent );
}