Beispiel #1
0
void BeatCounterAudioProcessor::processBlock(AudioSampleBuffer &buffer, MidiBuffer &midiMessages) {
    TeragonPluginBase::processBlock(buffer, midiMessages);

    for(int i = 0; i < buffer.getNumSamples(); ++i) {
        float currentSample = *buffer.getSampleData(0, i);
        double currentSampleAmplitude;

        if(filterEnabled) {
            // This relies on the sample rate which may not be available during initialization
            if(filterConstant == 0.0) {
                filterConstant = calculateFilterConstant(getSampleRate(), filterFrequency->getValue());
            }
            // Basic lowpass filter (feedback)
            filterOutput += (currentSample - filterOutput) / filterConstant;
            currentSampleAmplitude = fabs(filterOutput);
        }
        else {
            currentSampleAmplitude = fabs(currentSample);
        }

        // Find highest peak in the current period
        if(currentSampleAmplitude > highestAmplitudeInPeriod) {
            highestAmplitudeInPeriod = currentSampleAmplitude;

            // Is it also the highest value since we started?
            if(currentSampleAmplitude > highestAmplitude) {
                highestAmplitude = currentSampleAmplitude;
            }
        }

        // Downsample by skipping samples
        if(--samplesToSkip <= 0) {

            // Beat amplitude trigger has been detected
            if(highestAmplitudeInPeriod >= (highestAmplitude * tolerance->getValue() / 100.0) &&
                highestAmplitudeInPeriod > kSilenceThreshold) {

                // First sample inside of a beat?
                if(!currentlyInsideBeat && numSamplesSinceLastBeat > cooldownPeriodInSamples) {
                    currentlyInsideBeat = true;
                    double bpm = (getSampleRate() * 60.0f) / ((beatLengthRunningAverage + numSamplesSinceLastBeat) / 2);

                    // Check for half-beat patterns. For instance, a song which has a kick drum
                    // at around 70 BPM but an actual tempo of 140 BPM (hello, dubstep!).
                    double doubledBpm = bpm * 2.0;
                    if(doubledBpm > minimumAllowedBpm && doubledBpm < maximumAllowedBpm) {
                        bpm = doubledBpm;
                    }

                    beatLengthRunningAverage += numSamplesSinceLastBeat;
                    beatLengthRunningAverage /= 2;
                    numSamplesSinceLastBeat = 0;

                    // Check to see that this tempo is within the limits allowed
                    if(bpm > minimumAllowedBpm && bpm < maximumAllowedBpm) {
                        bpmHistory.push_back(bpm);
                        parameters.set("Beat Triggered", 1.0f);
                        parameters.set("Current BPM", bpm);

                        // Do total BPM and Reset?
                        if(numSamplesProcessed > period->getValue() * getSampleRate()) {
                            // Take advantage of this trigger point to do a tempo check and adjust the minimum
                            // and maximum BPM ranges accordingly.
                            if(useHostTempo->getValue()) {
                                minimumAllowedBpm = getHostTempo() - kHostTempoLinkToleranceInBpm;
                                maximumAllowedBpm = getHostTempo() + kHostTempoLinkToleranceInBpm;
                                cooldownPeriodInSamples = (unsigned long)(getSampleRate() * (60.0 / maximumAllowedBpm));
                            }

                            runningBpm = 0.0;
                            for(unsigned int historyIndex = 0; historyIndex < bpmHistory.size(); ++historyIndex) {
                                runningBpm += bpmHistory.at(historyIndex);
                            }
                            runningBpm /= (double)bpmHistory.size();
                            bpmHistory.clear();
                            numSamplesProcessed = 0;
                            parameters.set("Running BPM", runningBpm);
                        }
                    }
                    else {
                        // Outside of bpm threshold, ignore
                    }
                }
                else {
                    // Not the first beat mark
                    currentlyInsideBeat = false;
                }
            }
            else {
                // Were we just in a beat?
                if(currentlyInsideBeat) {
                    currentlyInsideBeat = false;
                }
            }

            samplesToSkip = kDownsampleFactor;
            highestAmplitudeInPeriod = 0.0;
        }

        ++numSamplesProcessed;
        ++numSamplesSinceLastBeat;
    }
}
Beispiel #2
0
  void BeatCounter::processBlock(AudioSampleBuffer& buffer, MidiBuffer& midiMessages) {
    for(int i = 0; i < buffer.getNumSamples(); ++i) {
      float* currentSample = buffer.getSampleData(0, i);
      double currentSampleAmplitude = 0.0f;

      if(this->isAutofilterEnabled) {
        // Basic lowpass filter (feedback)
        this->autofilterOutput += (*currentSample - this->autofilterOutput) / this->autofilterConstant;
        currentSampleAmplitude = fabs(this->autofilterOutput);
      }
      else {
        currentSampleAmplitude = fabs(*currentSample);
      }
      
      // Find highest peak in downsampled area ("bar")
      if(*currentSample > m_bar_high_point) {
        m_bar_high_point = *currentSample;
        
        // Find highest averaging value for testing period
        if(*currentSample > m_high_point) {
          m_high_point = *currentSample;
        }  
      }
      
      // Process one "bar"
      if(--m_skip_count <= 0) {
        // Calculate average point
        m_bar_samp_avg /= m_downsample_rate;
        
        // Beat amplitude/frequency has been detected
        if(m_bar_samp_avg >= (m_bar_high_avg * this->tolerance / 100.0) &&
           m_bar_high_point >= (m_high_point * this->tolerance / 100.0) &&
           m_bar_high_point > kSilenceThreshold) {
          
          // First bar in a beat?
          if(!m_beat_state && m_beat_samples > m_dupe_interval) {
            m_beat_state = true;
            double bpm = (getSampleRate() * 60.0f) / ((m_last_avg + m_beat_samples) / 2);
            
            // Check for half-beat patterns
            double hbpm = bpm * 2.0;
            if(hbpm > m_min_bpm && hbpm < m_max_bpm) {
              bpm = hbpm;
            }
            
            // See if we're inside the threshhold
            if(bpm > m_min_bpm && bpm < m_max_bpm) {
              this->currentBpm = bpm;

              m_last_avg += m_beat_samples;
              m_last_avg /= 2;
              m_beat_samples = 0;
              bpmHistory.push_back(bpm);
              
              // Do total BPM and Reset?
              if(m_num_samples_processed > (this->periodSizeInSamples * getSampleRate())) {
                // Take advantage of this trigger point to do a tempo check
                if(this->linkWithHostTempo) {
                  m_min_bpm = getHostTempo() - kHostTempoLinkToleranceInBpm;
                  m_max_bpm = getHostTempo() + kHostTempoLinkToleranceInBpm;
                  m_dupe_interval = (long)(getSampleRate() * (float)(60.0f / (float)m_max_bpm));
                }
                
                this->runningBpm = 0.0;
                for(unsigned int bpmHistoryIndex = 0; bpmHistoryIndex < bpmHistory.size(); ++bpmHistoryIndex) {
                  this->runningBpm += bpmHistory.at(bpmHistoryIndex);
                }
                bpmHistory.clear();
                m_num_samples_processed = 0;
              }
            }
            else {
              // Outside of bpm threshhold
              // TODO: Unset BPM Display in GUI
              m_last_avg += m_beat_samples;
              m_last_avg /= 2;
              m_beat_samples = 0;
            }
          }
          else {
            // Not the first beat mark
            m_beat_state = false;
          }
        }
        else {
          // Were we just in a beat?
          if(m_beat_state) {
            m_beat_state = false;
          }
        }
        
        m_skip_count = m_downsample_rate;
        m_bar_high_point = 0.0;
        m_bar_samp_avg = 0.0;
      }
      else {
        m_bar_samp_avg += *currentSample;
      }
      
      ++m_num_samples_processed;
      ++m_beat_samples;
    }
  }