void PixarDemo2012::generateWaveforms() { // DRAW MEM SPEHRES AND WAVEFORMS // Check init flag if ( mFft ) { // Get data in the frequency (transformed) and time domains float * freqData = mFft->getAmplitude(); float * timeData = mFft->getData(); int32_t dataSize = mFft->getBinSize(); // Cast data size to float float dataSizef = (float)dataSize; // Get dimensions float scale = ( (float)getWindowWidth() - 20.0f ) / dataSizef; float windowHeight = (float)getWindowHeight(); // Use polylines to depict time and frequency domains PolyLine<Vec2f> freqLine; PolyLine<Vec2f> timeLine; makeBall = 0.0f; float greatestFreq = 0.0; // Iterate through data for ( int32_t i = 0; i < dataSize; i++ ) { // Do logarithmic plotting for frequency domain float logSize = math<float>::log( dataSizef ); float x = (float)( ( math<float>::log( (float)i ) / logSize ) * dataSizef ); float y = math<float>::clamp( freqData[ i ] * ( x / dataSizef ) * ( math<float>::log( ( dataSizef - (float)i ) ) ), 0.0f, 2.0f ); if (y > makeBall) makeBall = y; if(y > greatestFreq) greatestFreq = y; // Plot points on lines for tme domain freqLine.push_back( Vec2f( x * scale + 10.0f, -y * ( windowHeight - 20.0f ) * 1.75f + ( windowHeight - 10.0f ) ) ); timeLine.push_back( Vec2f( (float)i * scale + 10.0f, timeData[ i ] * ( windowHeight - 20.0f ) * 0.25f + ( windowHeight * 0.25f + 10.0f ) ) ); } //printf("%f\n", greatestFreq); theMindField.SetAmps(greatestFreq); // Draw signals if ( drawFFT ) { gl::draw( freqLine ); gl::draw( timeLine ); } } }
// Draw void KissBasicApp::draw() { // Clear screen gl::clear( ColorAf::black() ); // Check init flag if ( mFft ) { // Get data in the frequency (transformed) and time domains float * freqData = mFft->getAmplitude(); float * timeData = mFft->getData(); int32_t dataSize = mFft->getBinSize(); // Cast data size to float float dataSizef = (float)dataSize; // Get dimensions float scale = ( (float)getWindowWidth() - 20.0f ) / dataSizef; float windowHeight = (float)getWindowHeight(); // Use polylines to depict time and frequency domains PolyLine<Vec2f> freqLine; PolyLine<Vec2f> timeLine; // Iterate through data for ( int32_t i = 0; i < dataSize; i++ ) { // Do logarithmic plotting for frequency domain float logSize = math<float>::log( dataSizef ); float x = (float)( (math<float>::log( (float)i) / logSize ) * dataSizef ); float y = math<float>::clamp( freqData[i] * ( x / dataSizef ) * ( math<float>::log( ( dataSizef - (float)i ) ) ), 0.0f, 2.0f ); // Plot points on lines for tme domain freqLine.push_back( Vec2f( x * scale + 10.0f, -y * ( windowHeight - 20.0f ) * 0.25f + ( windowHeight - 10.0f ) ) ); timeLine.push_back( Vec2f( (float)i * scale + 10.0f, timeData[ i ] * ( windowHeight - 20.0f ) * 0.25f + ( windowHeight * 0.25f + 10.0f ) ) ); } // Draw signals gl::draw( freqLine ); gl::draw( timeLine ); } }
// Runs update logic void KissTempoApp::update() { // Don't evaluate right away or unrealistically // high numbers will pop up if ( getElapsedSeconds() < 0.5 ) { return; } // Check if track is playing and has a PCM buffer available if ( mTrack && mTrack->isPlaying() && mTrack->isPcmBuffering() ) { // Get buffer mBuffer = mTrack->getPcmBuffer(); if ( mBuffer && mBuffer->getInterleavedData() ) { // Get sample count uint32_t sampleCount = mBuffer->getInterleavedData()->mSampleCount; if ( sampleCount > 0 ) { // Kiss is not initialized if ( !mFft ) { // Initialize analyzer mFft = Kiss::create( sampleCount ); // Set filter on FFT to calculate tempo based on beats mFft->setFilter( 0.2f, Kiss::Filter::LOW_PASS ); } // Analyze data if ( mBuffer->getInterleavedData()->mData != 0 ) { // Set FFT data mInputData = mBuffer->getInterleavedData()->mData; mInputSize = mBuffer->getInterleavedData()->mSampleCount; mFft->setData( mInputData ); // Get data mTimeData = mFft->getData(); mDataSize = mFft->getBinSize(); // Iterate through amplitude data for ( int32_t i = 0; i < mDataSize; i++, mSampleDistance++ ) { // Check value against threshold if ( mTimeData[ i ] >= mThreshold ) { // Determine neighbor range int32_t start = math<int32_t>::max( i - mNeighbors, 0 ); int32_t end = math<int32_t>::min( i + mNeighbors, mDataSize - 1 ); // Compare this value with neighbors to find peak bool peak = true; for ( int32_t j = start; j < end; j++ ) { if ( j != i && mTimeData[ i ] <= mTimeData[ j ] ) { peak = false; break; } } // This is a peak if ( peak ) { // Add distance between this peak and last into the // list. Just note position if this is the first peak. if ( mFirstPeak >= 0 ) { mPeakDistances.push_back( mSampleDistance ); } else { mFirstPeak = mSampleDistance; } // Reset distance counter mSampleDistance = 0; } } } } } // We have multiple peaks to compare if ( mPeakDistances.size() > 1 ) { // Add distances int32_t total = 0; uint32_t peakCount = mPeakDistances.size(); for ( uint32_t i = 0; i < peakCount; i++ ) { total += mPeakDistances[ i ]; } // Determine tempo based on average peak distance mTempo = total > 0 ? ( 44100.0f / ( (float)total / (float)mPeakDistances.size() ) ) * 60.0f / 1000.0f : 0.0f; } // Get current window height int32_t windowHeight = getWindowHeight() / 8; // Add up values, combine input and filtered values // to emphasize bass float total = 0.0f; for ( int32_t i = 0; i < mDataSize; i++ ) { if ( i * 8 < mInputSize ) { total += mTimeData[ i ] * 2.0f * mInputData[ i * 8 ]; } } // Add average to drawing line mWaveform.push_back( total / (float)mDataSize ); // Remove points when vector is wider than screen while ( mWaveform.size() >= (uint32_t)windowHeight ) { mWaveform.erase( mWaveform.begin() ); } } } }