<commit_before>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_processing/aec3/reverb_model_estimator.h"

#include <algorithm>
#include <array>
#include <cmath>
#include <memory>
#include <numeric>

#include "api/array_view.h"
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/field_trial.h"

namespace webrtc {

namespace {

bool EnableSmoothUpdatesTailFreqResp() {
  return !field_trial::IsEnabled(
      "WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch");
}

// Computes the ratio of the energies between the direct path and the tail. The
// energy is computed in the power spectrum domain discarding the DC
// contributions.
float ComputeRatioEnergies(
    const rtc::ArrayView<const float>& freq_resp_direct_path,
    const rtc::ArrayView<const float>& freq_resp_tail) {
  // Skipping the DC for the ratio computation
  constexpr size_t n_skip_bins = 1;
  RTC_CHECK_EQ(freq_resp_direct_path.size(), freq_resp_tail.size());

  float direct_path_energy =
      std::accumulate(freq_resp_direct_path.begin() + n_skip_bins,
                      freq_resp_direct_path.end(), 0.f);

  float tail_energy = std::accumulate(freq_resp_tail.begin() + n_skip_bins,
                                      freq_resp_tail.end(), 0.f);

  if (direct_path_energy > 0) {
    return tail_energy / direct_path_energy;
  } else {
    return 0.f;
  }
}

}  // namespace

ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config)
    : filter_main_length_blocks_(config.filter.main.length_blocks),
      reverb_decay_(std::fabs(config.ep_strength.default_len)),
      enable_smooth_freq_resp_tail_updates_(EnableSmoothUpdatesTailFreqResp()) {
  block_energies_.fill(0.f);
  freq_resp_tail_.fill(0.f);
}

ReverbModelEstimator::~ReverbModelEstimator() = default;

bool ReverbModelEstimator::IsAGoodFilterForDecayEstimation(
    int filter_delay_blocks,
    bool usable_linear_estimate,
    size_t length_filter) {
  if ((filter_delay_blocks && usable_linear_estimate) &&
      (filter_delay_blocks <=
       static_cast<int>(filter_main_length_blocks_) - 4) &&
      (length_filter >=
       static_cast<size_t>(GetTimeDomainLength(filter_main_length_blocks_)))) {
    return true;
  } else {
    return false;
  }
}

void ReverbModelEstimator::Update(
    const std::vector<float>& impulse_response,
    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
        filter_freq_response,
    const absl::optional<float>& quality_linear,
    int filter_delay_blocks,
    bool usable_linear_estimate,
    float default_decay,
    bool stationary_block) {
  if (enable_smooth_freq_resp_tail_updates_) {
    if (!stationary_block) {
      float alpha = 0;
      if (quality_linear) {
        alpha = 0.2f * quality_linear.value();
        UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, alpha);
      }
      if (IsAGoodFilterForDecayEstimation(filter_delay_blocks,
                                          usable_linear_estimate,
                                          impulse_response.size())) {
        alpha_ = std::max(alpha, alpha_);
        if ((alpha_ > 0.f) && (default_decay < 0.f)) {
          // Echo tail decay estimation if default_decay is negative.
          UpdateReverbDecay(impulse_response);
        }
      } else {
        ResetDecayEstimation();
      }
    }
  } else {
    UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, 0.1f);
  }
}

void ReverbModelEstimator::ResetDecayEstimation() {
  accumulated_nz_ = 0.f;
  accumulated_nn_ = 0.f;
  accumulated_count_ = 0.f;
  current_reverb_decay_section_ = 0;
  num_reverb_decay_sections_ = 0;
  num_reverb_decay_sections_next_ = 0;
  found_end_of_reverb_decay_ = false;
  alpha_ = 0.f;
}

void ReverbModelEstimator::UpdateReverbDecay(
    const std::vector<float>& impulse_response) {
  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;

  // Form the data to match against by squaring the impulse response
  // coefficients.
  std::array<float, GetTimeDomainLength(kMaxAdaptiveFilterLength)>
      matching_data_data;
  RTC_DCHECK_LE(GetTimeDomainLength(filter_main_length_blocks_),
                matching_data_data.size());
  rtc::ArrayView<float> matching_data(
      matching_data_data.data(),
      GetTimeDomainLength(filter_main_length_blocks_));
  std::transform(
      impulse_response.begin(), impulse_response.end(), matching_data.begin(),
      [](float a) { return a * a; });  // TODO(devicentepena) check if focusing
                                       // on one block would be enough.

  if (current_reverb_decay_section_ < filter_main_length_blocks_) {
    // Update accumulated variables for the current filter section.

    const size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;

    RTC_DCHECK_GT(matching_data.size(), start_index);
    RTC_DCHECK_GE(matching_data.size(), start_index + kFftLengthBy2);
    float section_energy =
        std::accumulate(matching_data.begin() + start_index,
                        matching_data.begin() + start_index + kFftLengthBy2,
                        0.f) *
        kOneByFftLengthBy2;

    section_energy = std::max(
        section_energy, 1e-32f);  // Regularization to avoid division by 0.

    RTC_DCHECK_LT(current_reverb_decay_section_, block_energies_.size());
    const float energy_ratio =
        block_energies_[current_reverb_decay_section_] / section_energy;

    found_end_of_reverb_decay_ = found_end_of_reverb_decay_ ||
                                 (energy_ratio > 1.1f || energy_ratio < 0.9f);

    // Count consecutive number of "good" filter sections, where "good" means:
    // 1) energy is above noise floor.
    // 2) energy of current section has not changed too much from last check.
    if (!found_end_of_reverb_decay_ && section_energy > tail_energy_) {
      ++num_reverb_decay_sections_next_;
    } else {
      found_end_of_reverb_decay_ = true;
    }

    block_energies_[current_reverb_decay_section_] = section_energy;

    if (num_reverb_decay_sections_ > 0) {
      // Linear regression of log squared magnitude of impulse response.
      for (size_t i = 0; i < kFftLengthBy2; i++) {
        RTC_DCHECK_GT(matching_data.size(), start_index + i);
        float z = FastApproxLog2f(matching_data[start_index + i] + 1e-10);
        accumulated_nz_ += accumulated_count_ * z;
        ++accumulated_count_;
      }
    }

    num_reverb_decay_sections_ =
        num_reverb_decay_sections_ > 0 ? num_reverb_decay_sections_ - 1 : 0;
    ++current_reverb_decay_section_;

  } else {
    constexpr float kMaxDecay = 0.95f;  // ~1 sec min RT60.
    constexpr float kMinDecay = 0.02f;  // ~15 ms max RT60.

    // Accumulated variables throughout whole filter.

    // Solve for decay rate.

    float decay = reverb_decay_;

    if (accumulated_nn_ != 0.f) {
      const float exp_candidate = -accumulated_nz_ / accumulated_nn_;
      decay = std::pow(2.0f, -exp_candidate * kFftLengthBy2);
      decay = std::min(decay, kMaxDecay);
      decay = std::max(decay, kMinDecay);
    }

    // Filter tail energy (assumed to be noise).
    constexpr size_t kTailLength = kFftLengthBy2;

    constexpr float k1ByTailLength = 1.f / kTailLength;
    const size_t tail_index =
        GetTimeDomainLength(filter_main_length_blocks_) - kTailLength;

    RTC_DCHECK_GT(matching_data.size(), tail_index);

    tail_energy_ = std::accumulate(matching_data.begin() + tail_index,
                                   matching_data.end(), 0.f) *
                   k1ByTailLength;

    // Update length of decay.
    num_reverb_decay_sections_ = num_reverb_decay_sections_next_;
    num_reverb_decay_sections_next_ = 0;
    // Must have enough data (number of sections) in order
    // to estimate decay rate.
    if (num_reverb_decay_sections_ < 5) {
      num_reverb_decay_sections_ = 0;
    }

    const float N = num_reverb_decay_sections_ * kFftLengthBy2;
    accumulated_nz_ = 0.f;
    const float k1By12 = 1.f / 12.f;
    // Arithmetic sum $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
    accumulated_nn_ = N * (N * N - 1.0f) * k1By12;
    accumulated_count_ = -N * 0.5f;
    // Linear regression approach assumes symmetric index around 0.
    accumulated_count_ += 0.5f;

    // Identify the peak index of the impulse response.
    const size_t peak_index = std::distance(
        matching_data.begin(),
        std::max_element(matching_data.begin(), matching_data.end()));

    current_reverb_decay_section_ = peak_index * kOneByFftLengthBy2 + 3;
    // Make sure we're not out of bounds.
    if (current_reverb_decay_section_ + 1 >= filter_main_length_blocks_) {
      current_reverb_decay_section_ = filter_main_length_blocks_;
    }
    size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
    float first_section_energy =
        std::accumulate(matching_data.begin() + start_index,
                        matching_data.begin() + start_index + kFftLengthBy2,
                        0.f) *
        kOneByFftLengthBy2;

    // To estimate the reverb decay, the energy of the first filter section
    // must be substantially larger than the last.
    // Also, the first filter section energy must not deviate too much
    // from the max peak.
    bool main_filter_has_reverb = first_section_energy > 4.f * tail_energy_;
    bool main_filter_is_sane = first_section_energy > 2.f * tail_energy_ &&
                               matching_data[peak_index] < 100.f;

    // Not detecting any decay, but tail is over noise - assume max decay.
    if (num_reverb_decay_sections_ == 0 && main_filter_is_sane &&
        main_filter_has_reverb) {
      decay = kMaxDecay;
    }

    if (main_filter_is_sane && num_reverb_decay_sections_ > 0) {
      decay = std::max(.97f * reverb_decay_, decay);
      reverb_decay_ -= alpha_ * (reverb_decay_ - decay);
    }

    found_end_of_reverb_decay_ =
        !(main_filter_is_sane && main_filter_has_reverb);
    alpha_ = 0.f;  // Stop estimation of the decay until another good filter is
                   // received
  }
}

// Updates the estimation of the frequency response at the filter tail.
void ReverbModelEstimator::UpdateFreqRespTail(
    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
        filter_freq_response,
    int filter_delay_blocks,
    float alpha) {
  size_t num_blocks = filter_freq_response.size();
  rtc::ArrayView<const float> freq_resp_tail(
      filter_freq_response[num_blocks - 1]);
  rtc::ArrayView<const float> freq_resp_direct_path(
      filter_freq_response[filter_delay_blocks]);
  float ratio_energies =
      ComputeRatioEnergies(freq_resp_direct_path, freq_resp_tail);
  ratio_tail_to_direct_path_ +=
      alpha * (ratio_energies - ratio_tail_to_direct_path_);

  for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
    freq_resp_tail_[k] = freq_resp_direct_path[k] * ratio_tail_to_direct_path_;
  }

  for (size_t k = 1; k < kFftLengthBy2; ++k) {
    float avg_neighbour =
        0.5f * (freq_resp_tail_[k - 1] + freq_resp_tail_[k + 1]);
    freq_resp_tail_[k] = std::max(freq_resp_tail_[k], avg_neighbour);
  }
}

void ReverbModelEstimator::Dump(
    const std::unique_ptr<ApmDataDumper>& data_dumper) {
  data_dumper->DumpRaw("aec3_reverb_decay", reverb_decay_);
  data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_energy_);
  data_dumper->DumpRaw("aec3_reverb_alpha", alpha_);
  data_dumper->DumpRaw("aec3_num_reverb_decay_sections",
                       static_cast<int>(num_reverb_decay_sections_));
}

}  // namespace webrtc
<commit_msg>Revert "IWYU: Add <cmath> for fabsf() and powf(), switch to C++ versions"<commit_after>/*
 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_processing/aec3/reverb_model_estimator.h"

#include <algorithm>
#include <array>
#include <memory>
#include <numeric>

#include "api/array_view.h"
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/field_trial.h"

namespace webrtc {

namespace {

bool EnableSmoothUpdatesTailFreqResp() {
  return !field_trial::IsEnabled(
      "WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch");
}

// Computes the ratio of the energies between the direct path and the tail. The
// energy is computed in the power spectrum domain discarding the DC
// contributions.
float ComputeRatioEnergies(
    const rtc::ArrayView<const float>& freq_resp_direct_path,
    const rtc::ArrayView<const float>& freq_resp_tail) {
  // Skipping the DC for the ratio computation
  constexpr size_t n_skip_bins = 1;
  RTC_CHECK_EQ(freq_resp_direct_path.size(), freq_resp_tail.size());

  float direct_path_energy =
      std::accumulate(freq_resp_direct_path.begin() + n_skip_bins,
                      freq_resp_direct_path.end(), 0.f);

  float tail_energy = std::accumulate(freq_resp_tail.begin() + n_skip_bins,
                                      freq_resp_tail.end(), 0.f);

  if (direct_path_energy > 0) {
    return tail_energy / direct_path_energy;
  } else {
    return 0.f;
  }
}

}  // namespace

ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config)
    : filter_main_length_blocks_(config.filter.main.length_blocks),
      reverb_decay_(fabsf(config.ep_strength.default_len)),
      enable_smooth_freq_resp_tail_updates_(EnableSmoothUpdatesTailFreqResp()) {
  block_energies_.fill(0.f);
  freq_resp_tail_.fill(0.f);
}

ReverbModelEstimator::~ReverbModelEstimator() = default;

bool ReverbModelEstimator::IsAGoodFilterForDecayEstimation(
    int filter_delay_blocks,
    bool usable_linear_estimate,
    size_t length_filter) {
  if ((filter_delay_blocks && usable_linear_estimate) &&
      (filter_delay_blocks <=
       static_cast<int>(filter_main_length_blocks_) - 4) &&
      (length_filter >=
       static_cast<size_t>(GetTimeDomainLength(filter_main_length_blocks_)))) {
    return true;
  } else {
    return false;
  }
}

void ReverbModelEstimator::Update(
    const std::vector<float>& impulse_response,
    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
        filter_freq_response,
    const absl::optional<float>& quality_linear,
    int filter_delay_blocks,
    bool usable_linear_estimate,
    float default_decay,
    bool stationary_block) {
  if (enable_smooth_freq_resp_tail_updates_) {
    if (!stationary_block) {
      float alpha = 0;
      if (quality_linear) {
        alpha = 0.2f * quality_linear.value();
        UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, alpha);
      }
      if (IsAGoodFilterForDecayEstimation(filter_delay_blocks,
                                          usable_linear_estimate,
                                          impulse_response.size())) {
        alpha_ = std::max(alpha, alpha_);
        if ((alpha_ > 0.f) && (default_decay < 0.f)) {
          // Echo tail decay estimation if default_decay is negative.
          UpdateReverbDecay(impulse_response);
        }
      } else {
        ResetDecayEstimation();
      }
    }
  } else {
    UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, 0.1f);
  }
}

void ReverbModelEstimator::ResetDecayEstimation() {
  accumulated_nz_ = 0.f;
  accumulated_nn_ = 0.f;
  accumulated_count_ = 0.f;
  current_reverb_decay_section_ = 0;
  num_reverb_decay_sections_ = 0;
  num_reverb_decay_sections_next_ = 0;
  found_end_of_reverb_decay_ = false;
  alpha_ = 0.f;
}

void ReverbModelEstimator::UpdateReverbDecay(
    const std::vector<float>& impulse_response) {
  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;

  // Form the data to match against by squaring the impulse response
  // coefficients.
  std::array<float, GetTimeDomainLength(kMaxAdaptiveFilterLength)>
      matching_data_data;
  RTC_DCHECK_LE(GetTimeDomainLength(filter_main_length_blocks_),
                matching_data_data.size());
  rtc::ArrayView<float> matching_data(
      matching_data_data.data(),
      GetTimeDomainLength(filter_main_length_blocks_));
  std::transform(
      impulse_response.begin(), impulse_response.end(), matching_data.begin(),
      [](float a) { return a * a; });  // TODO(devicentepena) check if focusing
                                       // on one block would be enough.

  if (current_reverb_decay_section_ < filter_main_length_blocks_) {
    // Update accumulated variables for the current filter section.

    const size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;

    RTC_DCHECK_GT(matching_data.size(), start_index);
    RTC_DCHECK_GE(matching_data.size(), start_index + kFftLengthBy2);
    float section_energy =
        std::accumulate(matching_data.begin() + start_index,
                        matching_data.begin() + start_index + kFftLengthBy2,
                        0.f) *
        kOneByFftLengthBy2;

    section_energy = std::max(
        section_energy, 1e-32f);  // Regularization to avoid division by 0.

    RTC_DCHECK_LT(current_reverb_decay_section_, block_energies_.size());
    const float energy_ratio =
        block_energies_[current_reverb_decay_section_] / section_energy;

    found_end_of_reverb_decay_ = found_end_of_reverb_decay_ ||
                                 (energy_ratio > 1.1f || energy_ratio < 0.9f);

    // Count consecutive number of "good" filter sections, where "good" means:
    // 1) energy is above noise floor.
    // 2) energy of current section has not changed too much from last check.
    if (!found_end_of_reverb_decay_ && section_energy > tail_energy_) {
      ++num_reverb_decay_sections_next_;
    } else {
      found_end_of_reverb_decay_ = true;
    }

    block_energies_[current_reverb_decay_section_] = section_energy;

    if (num_reverb_decay_sections_ > 0) {
      // Linear regression of log squared magnitude of impulse response.
      for (size_t i = 0; i < kFftLengthBy2; i++) {
        RTC_DCHECK_GT(matching_data.size(), start_index + i);
        float z = FastApproxLog2f(matching_data[start_index + i] + 1e-10);
        accumulated_nz_ += accumulated_count_ * z;
        ++accumulated_count_;
      }
    }

    num_reverb_decay_sections_ =
        num_reverb_decay_sections_ > 0 ? num_reverb_decay_sections_ - 1 : 0;
    ++current_reverb_decay_section_;

  } else {
    constexpr float kMaxDecay = 0.95f;  // ~1 sec min RT60.
    constexpr float kMinDecay = 0.02f;  // ~15 ms max RT60.

    // Accumulated variables throughout whole filter.

    // Solve for decay rate.

    float decay = reverb_decay_;

    if (accumulated_nn_ != 0.f) {
      const float exp_candidate = -accumulated_nz_ / accumulated_nn_;
      decay = powf(2.0f, -exp_candidate * kFftLengthBy2);
      decay = std::min(decay, kMaxDecay);
      decay = std::max(decay, kMinDecay);
    }

    // Filter tail energy (assumed to be noise).
    constexpr size_t kTailLength = kFftLengthBy2;

    constexpr float k1ByTailLength = 1.f / kTailLength;
    const size_t tail_index =
        GetTimeDomainLength(filter_main_length_blocks_) - kTailLength;

    RTC_DCHECK_GT(matching_data.size(), tail_index);

    tail_energy_ = std::accumulate(matching_data.begin() + tail_index,
                                   matching_data.end(), 0.f) *
                   k1ByTailLength;

    // Update length of decay.
    num_reverb_decay_sections_ = num_reverb_decay_sections_next_;
    num_reverb_decay_sections_next_ = 0;
    // Must have enough data (number of sections) in order
    // to estimate decay rate.
    if (num_reverb_decay_sections_ < 5) {
      num_reverb_decay_sections_ = 0;
    }

    const float N = num_reverb_decay_sections_ * kFftLengthBy2;
    accumulated_nz_ = 0.f;
    const float k1By12 = 1.f / 12.f;
    // Arithmetic sum $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
    accumulated_nn_ = N * (N * N - 1.0f) * k1By12;
    accumulated_count_ = -N * 0.5f;
    // Linear regression approach assumes symmetric index around 0.
    accumulated_count_ += 0.5f;

    // Identify the peak index of the impulse response.
    const size_t peak_index = std::distance(
        matching_data.begin(),
        std::max_element(matching_data.begin(), matching_data.end()));

    current_reverb_decay_section_ = peak_index * kOneByFftLengthBy2 + 3;
    // Make sure we're not out of bounds.
    if (current_reverb_decay_section_ + 1 >= filter_main_length_blocks_) {
      current_reverb_decay_section_ = filter_main_length_blocks_;
    }
    size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
    float first_section_energy =
        std::accumulate(matching_data.begin() + start_index,
                        matching_data.begin() + start_index + kFftLengthBy2,
                        0.f) *
        kOneByFftLengthBy2;

    // To estimate the reverb decay, the energy of the first filter section
    // must be substantially larger than the last.
    // Also, the first filter section energy must not deviate too much
    // from the max peak.
    bool main_filter_has_reverb = first_section_energy > 4.f * tail_energy_;
    bool main_filter_is_sane = first_section_energy > 2.f * tail_energy_ &&
                               matching_data[peak_index] < 100.f;

    // Not detecting any decay, but tail is over noise - assume max decay.
    if (num_reverb_decay_sections_ == 0 && main_filter_is_sane &&
        main_filter_has_reverb) {
      decay = kMaxDecay;
    }

    if (main_filter_is_sane && num_reverb_decay_sections_ > 0) {
      decay = std::max(.97f * reverb_decay_, decay);
      reverb_decay_ -= alpha_ * (reverb_decay_ - decay);
    }

    found_end_of_reverb_decay_ =
        !(main_filter_is_sane && main_filter_has_reverb);
    alpha_ = 0.f;  // Stop estimation of the decay until another good filter is
                   // received
  }
}

// Updates the estimation of the frequency response at the filter tail.
void ReverbModelEstimator::UpdateFreqRespTail(
    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
        filter_freq_response,
    int filter_delay_blocks,
    float alpha) {
  size_t num_blocks = filter_freq_response.size();
  rtc::ArrayView<const float> freq_resp_tail(
      filter_freq_response[num_blocks - 1]);
  rtc::ArrayView<const float> freq_resp_direct_path(
      filter_freq_response[filter_delay_blocks]);
  float ratio_energies =
      ComputeRatioEnergies(freq_resp_direct_path, freq_resp_tail);
  ratio_tail_to_direct_path_ +=
      alpha * (ratio_energies - ratio_tail_to_direct_path_);

  for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
    freq_resp_tail_[k] = freq_resp_direct_path[k] * ratio_tail_to_direct_path_;
  }

  for (size_t k = 1; k < kFftLengthBy2; ++k) {
    float avg_neighbour =
        0.5f * (freq_resp_tail_[k - 1] + freq_resp_tail_[k + 1]);
    freq_resp_tail_[k] = std::max(freq_resp_tail_[k], avg_neighbour);
  }
}

void ReverbModelEstimator::Dump(
    const std::unique_ptr<ApmDataDumper>& data_dumper) {
  data_dumper->DumpRaw("aec3_reverb_decay", reverb_decay_);
  data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_energy_);
  data_dumper->DumpRaw("aec3_reverb_alpha", alpha_);
  data_dumper->DumpRaw("aec3_num_reverb_decay_sections",
                       static_cast<int>(num_reverb_decay_sections_));
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "CongestionControllerLogic.h"

#include <cmath>

namespace facebook {
namespace memcache {

namespace {

/**
 * Base probability: the lowest probability a client sends.
 * This value is initialized to 10^-1.
 */
constexpr double kBaseProbability = 0.1;

/**
 * Pecentage of the effect of a value after the delay_ window. Default to 0.1,
 * which is 10%. We keep the residue in the log form so that the residue can be
 * specified more intuitively. For example, if need 20% of residue, we only need
 * to update this value to log10(0.2).
 */
const double kLogResidue = log10(0.1);

bool readProcStat(
    std::array<char, 320>& buf,
    std::array<uint64_t, 4>& curArray) {
  auto cpuStatFile = folly::File("/proc/stat");

  if (folly::readNoInt(cpuStatFile.fd(), buf.data(), buf.size()) !=
      buf.size()) {
    return false;
  }

  if (sscanf(
          buf.data(),
          "cpu %lu %lu %lu %lu",
          &curArray[0],
          &curArray[1],
          &curArray[2],
          &curArray[3]) != curArray.size()) {
    return false;
  }

  return true;
}

} // anonymous

CongestionControllerLogic::CongestionControllerLogic(
    uint64_t target,
    std::chrono::milliseconds delay,
    bool enableCPUControl,
    size_t queueCapacity)
    : target_(target),
      delay_(delay),
      enableCPUControl_(enableCPUControl),
      valueQueue_(queueCapacity) {
  // This thread updates the probability every delay_.
  probabilityUpdateThread_ = std::thread([this]() {
    while (keepRunning_) {
      // sleep override
      std::this_thread::sleep_for(delay_);

      // Get a copy the counter value.
      uint32_t curUpdateCounter = updateCounter_;

      /**
       * Corner case: If nothing is received this window, reset the
       * sendProbability_ to 1.
       */
      if (curUpdateCounter == 0) {
        sendProbability_ = 1.0;
        continue;
      }

      // Reset the counter.
      updateCounter_ -= curUpdateCounter;

      // Get a copy of the current weightedValue_.
      double curWeightedValue = weightedValue_;
      // Get a copy of the current sendProbability_.
      double curSendProbability = sendProbability_;

      if (firstWindow_) {
        curWeightedValue /= curUpdateCounter;
        firstWindow_ = false;
      }

      /**
       * Current adjustment factor. Default set sendProbability = 1.0 if
       * curWeightedValue is close to 0.
       */
      if (curWeightedValue > 0.000001) {
        // Update the send probability.
        curSendProbability *= target_ / curWeightedValue;
      } else {
        curSendProbability = 1.0;
      }

      if (curSendProbability < kBaseProbability) {
        curSendProbability = kBaseProbability;
      } else if (curSendProbability > 1.0) {
        curSendProbability = 1.0;
      }

      // Update the atomic probability here.
      sendProbability_ = curSendProbability;

      /* Update the smoothingFactor_.
       *
       * We want the effect of current update fades after delay_, so
       * we keep the curUpdateCounter and increase it on every updateValue call.
       *
       * Suppose the target smoothingFactor_ is x, then we want
       *
       *    x^curUpdateCounter < fadeThreshold
       *
       * which we set the fadeThreshold to 10%
       *
       *    x^curUpdateCounter = 10^-1
       *
       * then x = 10^(-1 / curUpdateCounter)
       */
      smoothingFactor_ =
          pow(10, kLogResidue / static_cast<double>(curUpdateCounter));
    }
  });

  // This thread reads value from the valueQueue_, if any.
  weightedValueUpdateThread_ = std::thread([this]() {
    double curValue{0.0};

    while (keepRunning_) {
      if (valueQueue_.isEmpty()) {
        // sleep override
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        continue;
      }

      if (!valueQueue_.read(curValue)) {
        curValue = 0.0;
      }

      // Update the counter before updating weightedValue_.
      ++updateCounter_;

      if (firstWindow_) {
        weightedValue_ = weightedValue_ + curValue;
      } else {
        weightedValue_ = smoothingFactor_ * weightedValue_ +
            (1.0 - smoothingFactor_) * curValue;
      }
    }
  });

  if (!enableCPUControl_) {
    return;
  }

  // Compute the cpu utilization
  cpuLoggingThread_ = std::thread([this]() {
    std::array<uint64_t, 4> prev;
    std::array<uint64_t, 4> cur;
    double cpuUtil = 0.0;
    bool isFirst = true;

    // Enough storage for the /proc/stat CPU data needed below
    std::array<char, 320> buf;

    while (keepRunning_) {
      // sleep override
      std::this_thread::sleep_for(std::chrono::milliseconds(10));

      // Corner case: When parsing /proc/stat fails, set the cpuUtil to 0.
      if (!readProcStat(buf, cur)) {
        updateValue(0.0);
        continue;
      }

      if (isFirst) {
        isFirst = false;
      } else {
        /**
         * The values in the /proc/stat is the CPU time since boot.
         * 1st column is user, 2nd column is nice, 3rd column is system, and
         * the 4th column is idle. The total CPU time in the last window is
         * delta busy time over delta total time.
         */
        auto curUtil = cur[0] + cur[1] + cur[2];
        auto prevUtil = prev[0] + prev[1] + prev[2];
        auto utilDiff = static_cast<double>(curUtil - prevUtil);
        auto totalDiff = utilDiff + cur[3] - prev[3];

        /**
         * Corner case: If CPU didn't change or the proc/stat didn't get
         * updated or ticks didn't increase, set the cpuUtil to 0.
         */
        if (totalDiff < 0.001 || curUtil < prevUtil) {
          cpuUtil = 0.0;
        } else {
          // Corner case: The max of CPU utilization can be at most 100%.
          cpuUtil = std::min((utilDiff / totalDiff) * 100, 100.0);
        }

        updateValue(cpuUtil);
      }

      prev = cur;
    }
  });
}

CongestionControllerLogic::~CongestionControllerLogic() {
  keepRunning_ = false;

  probabilityUpdateThread_.join();
  weightedValueUpdateThread_.join();

  if (enableCPUControl_) {
    cpuLoggingThread_.join();
  }
}

void CongestionControllerLogic::updateValue(double value) {
  // Remove contention by using a queue here.
  valueQueue_.write(value);
}

double CongestionControllerLogic::getDropProbability() const {
  return 1.0 - sendProbability_;
}

void CongestionControllerLogic::setTarget(uint64_t target) {
  target_ = target;
}

} // memcache
} // facebook
<commit_msg>Make updateCounter and curWeightedValue more accurate<commit_after>/*
 *  Copyright (c) 2016, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "CongestionControllerLogic.h"

#include <cmath>

namespace facebook {
namespace memcache {

namespace {

/**
 * Base probability: the lowest probability a client sends.
 * This value is initialized to 10^-1.
 */
constexpr double kBaseProbability = 0.1;

/**
 * Pecentage of the effect of a value after the delay_ window. Default to 0.1,
 * which is 10%. We keep the residue in the log form so that the residue can be
 * specified more intuitively. For example, if need 20% of residue, we only need
 * to update this value to log10(0.2).
 */
const double kLogResidue = log10(0.1);

bool readProcStat(
    std::array<char, 320>& buf,
    std::array<uint64_t, 4>& curArray) {
  auto cpuStatFile = folly::File("/proc/stat");

  if (folly::readNoInt(cpuStatFile.fd(), buf.data(), buf.size()) !=
      buf.size()) {
    return false;
  }

  if (sscanf(
          buf.data(),
          "cpu %lu %lu %lu %lu",
          &curArray[0],
          &curArray[1],
          &curArray[2],
          &curArray[3]) != curArray.size()) {
    return false;
  }

  return true;
}

} // anonymous

CongestionControllerLogic::CongestionControllerLogic(
    uint64_t target,
    std::chrono::milliseconds delay,
    bool enableCPUControl,
    size_t queueCapacity)
    : target_(target),
      delay_(delay),
      enableCPUControl_(enableCPUControl),
      valueQueue_(queueCapacity) {
  // This thread updates the probability every delay_.
  probabilityUpdateThread_ = std::thread([this]() {
    while (keepRunning_) {
      // sleep override
      std::this_thread::sleep_for(delay_);

      // Get a copy of the current sendProbability_.
      double curSendProbability = sendProbability_;
      // Get a copy the counter value.
      uint32_t curUpdateCounter = updateCounter_;
      // Get a copy of the current weightedValue_.
      double curWeightedValue = weightedValue_;

      /**
       * Corner case: If nothing is received this window, reset the
       * sendProbability_ to 1.
       */
      if (curUpdateCounter == 0) {
        sendProbability_ = 1.0;
        continue;
      }

      if (firstWindow_) {
        curWeightedValue /= curUpdateCounter;
        firstWindow_ = false;
      }

      /**
       * Current adjustment factor. Default set sendProbability = 1.0 if
       * curWeightedValue is close to 0.
       */
      if (curWeightedValue > 0.000001) {
        // Update the send probability.
        curSendProbability *= target_ / curWeightedValue;
      } else {
        curSendProbability = 1.0;
      }

      if (curSendProbability < kBaseProbability) {
        curSendProbability = kBaseProbability;
      } else if (curSendProbability > 1.0) {
        curSendProbability = 1.0;
      }

      // Update the atomic probability here.
      sendProbability_ = curSendProbability;

      // Reset the counter.
      updateCounter_ -= curUpdateCounter;

      /* Update the smoothingFactor_.
       *
       * We want the effect of current update fades after delay_, so
       * we keep the curUpdateCounter and increase it on every updateValue call.
       *
       * Suppose the target smoothingFactor_ is x, then we want
       *
       *    x^curUpdateCounter < fadeThreshold
       *
       * which we set the fadeThreshold to 10%
       *
       *    x^curUpdateCounter = 10^-1
       *
       * then x = 10^(-1 / curUpdateCounter)
       */
      smoothingFactor_ =
          pow(10, kLogResidue / static_cast<double>(curUpdateCounter));
    }
  });

  // This thread reads value from the valueQueue_, if any.
  weightedValueUpdateThread_ = std::thread([this]() {
    double curValue{0.0};

    while (keepRunning_) {
      if (valueQueue_.isEmpty()) {
        // sleep override
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        continue;
      }

      if (!valueQueue_.read(curValue)) {
        curValue = 0.0;
      }

      // Update the counter before updating weightedValue_.
      ++updateCounter_;

      if (firstWindow_) {
        weightedValue_ = weightedValue_ + curValue;
      } else {
        weightedValue_ = smoothingFactor_ * weightedValue_ +
            (1.0 - smoothingFactor_) * curValue;
      }
    }
  });

  if (!enableCPUControl_) {
    return;
  }

  // Compute the cpu utilization
  cpuLoggingThread_ = std::thread([this]() {
    std::array<uint64_t, 4> prev;
    std::array<uint64_t, 4> cur;
    double cpuUtil = 0.0;
    bool isFirst = true;

    // Enough storage for the /proc/stat CPU data needed below
    std::array<char, 320> buf;

    while (keepRunning_) {
      // sleep override
      std::this_thread::sleep_for(std::chrono::milliseconds(10));

      // Corner case: When parsing /proc/stat fails, set the cpuUtil to 0.
      if (!readProcStat(buf, cur)) {
        updateValue(0.0);
        continue;
      }

      if (isFirst) {
        isFirst = false;
      } else {
        /**
         * The values in the /proc/stat is the CPU time since boot.
         * 1st column is user, 2nd column is nice, 3rd column is system, and
         * the 4th column is idle. The total CPU time in the last window is
         * delta busy time over delta total time.
         */
        auto curUtil = cur[0] + cur[1] + cur[2];
        auto prevUtil = prev[0] + prev[1] + prev[2];
        auto utilDiff = static_cast<double>(curUtil - prevUtil);
        auto totalDiff = utilDiff + cur[3] - prev[3];

        /**
         * Corner case: If CPU didn't change or the proc/stat didn't get
         * updated or ticks didn't increase, set the cpuUtil to 0.
         */
        if (totalDiff < 0.001 || curUtil < prevUtil) {
          cpuUtil = 0.0;
        } else {
          // Corner case: The max of CPU utilization can be at most 100%.
          cpuUtil = std::min((utilDiff / totalDiff) * 100, 100.0);
        }

        updateValue(cpuUtil);
      }

      prev = cur;
    }
  });
}

CongestionControllerLogic::~CongestionControllerLogic() {
  keepRunning_ = false;

  probabilityUpdateThread_.join();
  weightedValueUpdateThread_.join();

  if (enableCPUControl_) {
    cpuLoggingThread_.join();
  }
}

void CongestionControllerLogic::updateValue(double value) {
  // Remove contention by using a queue here.
  valueQueue_.write(value);
}

double CongestionControllerLogic::getDropProbability() const {
  return 1.0 - sendProbability_;
}

void CongestionControllerLogic::setTarget(uint64_t target) {
  target_ = target;
}

} // memcache
} // facebook
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <iostream>
#include <Context.h>
#include <util.h>
#include <text.h>
#include <i18n.h>
#include <main.h>
#include <CmdDone.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdDone::CmdDone ()
{
  _keyword     = "done";
  _usage       = "task <filter> done <mods>";
  _description = STRING_CMD_DONE_USAGE;
  _read_only   = false;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdDone::execute (std::string& output)
{
  int rc = 0;
  int count = 0;

  // Apply filter.
  std::vector <Task> filtered;
  filter (filtered);
  if (filtered.size () == 0)
  {
    context.footnote (STRING_FEEDBACK_NO_TASKS_SP);
    return 1;
  }

  // Apply the command line modifications to the new task.
  A3 modifications = context.a3.extract_modifications ();

  // Accumulated project change notifications.
  std::map <std::string, std::string> projectChanges;

  bool nagged = false;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    Task before (*task);

    if (task->getStatus () == Task::pending ||
        task->getStatus () == Task::waiting)
    {
      // Complete the specified task.
      std::string question = format (STRING_CMD_DONE_CONFIRM,
                                     task->id,
                                     task->get ("description"));

      modify_task_annotate (*task, modifications);
      task->setStatus (Task::completed);
      if (! task->has ("end"))
        task->setEnd ();

      // Stop the task, if started.
      if (task->has ("start") &&
          context.config.getBoolean ("journal.time"))
        task->addAnnotation (context.config.get ("journal.time.stop.annotation"));

      if (permission (*task, taskDifferences (before, *task) + question, filtered.size ()))
      {
        updateRecurrenceMask (*task);
        context.tdb2.modify (*task);
        ++count;
        feedback_affected (STRING_CMD_DONE_TASK, *task);
        feedback_unblocked (*task);
        if (!nagged)
          nagged = nag (*task);
        dependencyChainOnComplete (*task);
        if (context.verbose ("project"))
          projectChanges[task->get ("project")] = onProjectChange (*task);
      }
      else
      {
        std::cout << STRING_CMD_DONE_NO << "\n";
        rc = 1;
        if (_permission_quit)
          break;
      }
    }
    else
    {
      std::cout << format (STRING_CMD_DONE_NOTPEND,
                           task->id,
                           task->get ("description"))
                << "\n";
      rc = 1;
    }
  }

  // Now list the project changes.
  std::map <std::string, std::string>::iterator i;
  for (i = projectChanges.begin (); i != projectChanges.end (); ++i)
    if (i->first != "")
      context.footnote (i->second);

  context.tdb2.commit ();
  feedback_affected (count == 1 ? STRING_CMD_DONE_1 : STRING_CMD_DONE_N, count);
  return rc;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>CmdDone<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <iostream>
#include <Context.h>
#include <Filter.h>
#include <util.h>
#include <text.h>
#include <i18n.h>
#include <main.h>
#include <CmdDone.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdDone::CmdDone ()
{
  _keyword     = "done";
  _usage       = "task <filter> done <mods>";
  _description = STRING_CMD_DONE_USAGE;
  _read_only   = false;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdDone::execute (std::string& output)
{
  int rc = 0;
  int count = 0;

  // Apply filter.
  Filter filter;
  std::vector <Task> filtered;
  filter.subset (filtered);
  if (filtered.size () == 0)
  {
    context.footnote (STRING_FEEDBACK_NO_TASKS_SP);
    return 1;
  }

  // Apply the command line modifications to the new task.
  A3 modifications = context.a3.extract_modifications ();

  // Accumulated project change notifications.
  std::map <std::string, std::string> projectChanges;

  bool nagged = false;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    Task before (*task);

    if (task->getStatus () == Task::pending ||
        task->getStatus () == Task::waiting)
    {
      // Complete the specified task.
      std::string question = format (STRING_CMD_DONE_CONFIRM,
                                     task->id,
                                     task->get ("description"));

      modify_task_annotate (*task, modifications);
      task->setStatus (Task::completed);
      if (! task->has ("end"))
        task->setEnd ();

      // Stop the task, if started.
      if (task->has ("start") &&
          context.config.getBoolean ("journal.time"))
        task->addAnnotation (context.config.get ("journal.time.stop.annotation"));

      if (permission (*task, taskDifferences (before, *task) + question, filtered.size ()))
      {
        updateRecurrenceMask (*task);
        context.tdb2.modify (*task);
        ++count;
        feedback_affected (STRING_CMD_DONE_TASK, *task);
        feedback_unblocked (*task);
        if (!nagged)
          nagged = nag (*task);
        dependencyChainOnComplete (*task);
        if (context.verbose ("project"))
          projectChanges[task->get ("project")] = onProjectChange (*task);
      }
      else
      {
        std::cout << STRING_CMD_DONE_NO << "\n";
        rc = 1;
        if (_permission_quit)
          break;
      }
    }
    else
    {
      std::cout << format (STRING_CMD_DONE_NOTPEND,
                           task->id,
                           task->get ("description"))
                << "\n";
      rc = 1;
    }
  }

  // Now list the project changes.
  std::map <std::string, std::string>::iterator i;
  for (i = projectChanges.begin (); i != projectChanges.end (); ++i)
    if (i->first != "")
      context.footnote (i->second);

  context.tdb2.commit ();
  feedback_affected (count == 1 ? STRING_CMD_DONE_1 : STRING_CMD_DONE_N, count);
  return rc;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>/**
 *	@file		value.hpp
 *	@author		seonho.oh@gmail.com
 *	@date		2013-11-01
 *	@copyright	2007-2013 seonho.oh@gmail.com, Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
 *	@version	1.0
 */

#pragma once

#include "jsoncxx.hpp"
#include <regex>

namespace jsoncxx
{

///////////////////////////////////////////////////////////////////////////////
// ParseType

//! Combination of parse flag
enum ParseFlag : unsigned int
{
	ParseDefault,	//!< Default parse type. Non-destructive parsing. Text strings are decoded into allocated buffer.
	ParseInplace	//!< Inplace(destructive) parsing.
};

///////////////////////////////////////////////////////////////////////////////
// SkipWhitespace
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
// Version 0.1

//! Skip the JSON white spaces in a stream.
/*! \param stream A input stream for skipping white spaces.
	\note This function has SSE2/SSE4.2 specialization.
*/
template<typename Stream>
void SkipWhitespace(Stream& stream) {
	Stream s = stream;	// Use a local copy for optimization
	while (s.peek() == ' ' || s.peek() == '\n' || s.peek() == '\r' || s.peek() == '\t')
		s.take();
	stream = s;
}

#ifdef JSONCXX_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) {
	static const char whitespace[16] = " \n\r\t";
	__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);

	for (;;) {
		__m128i s = _mm_loadu_si128((const __m128i *)p);
		unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
		if (r == 0)	// all 16 characters are whitespace
			p += 16;
		else {		// some of characters may be non-whitespace
#ifdef _MSC_VER		// Find the index of first non-whitespace
			unsigned long offset;
			if (_BitScanForward(&offset, r))
				return p + offset;
#else
			if (r != 0)
				return p + __builtin_ffs(r) - 1;
#endif
		}
	}
}

#elif defined(JSONCXX_SSE2)

//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) {
	static const char whitespaces[4][17] = {
		"                ",
		"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
		"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};

	__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
	__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
	__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
	__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);

	for (;;) {
		__m128i s = _mm_loadu_si128((const __m128i *)p);
		__m128i x = _mm_cmpeq_epi8(s, w0);
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
		unsigned short r = ~_mm_movemask_epi8(x);
		if (r == 0)	// all 16 characters are whitespace
			p += 16;
		else {		// some of characters may be non-whitespace
#ifdef _MSC_VER		// Find the index of first non-whitespace
			unsigned long offset;
			if (_BitScanForward(&offset, r))
				return p + offset;
#else
			if (r != 0)
				return p + __builtin_ffs(r) - 1;
#endif
		}
	}
}

#endif // JSONCXX_SSE2

#ifdef JSONCXX_SIMD
//! Template function specialization for inplace_stringstream
template<> inline void SkipWhitespace(inplace_stringstream& stream) {
	stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
}

//! Template function specialization for stringstream
template<> inline void SkipWhitespace(stringstream& stream) {
	stream.src_ = SkipWhitespace_SIMD(stream.src_);
}
#endif // JSONCXX_SIMD

template <typename Stream, typename Encoding = UTF8<> >
class generic_reader
{
public:
	typedef typename Encoding::char_type char_type;

	//! ctor
	generic_reader() {}

	//bool hasParseError() const { return parseError_ != nullptr; }
	//const char* getParseError() const { return parseError_; }
	//size_type getErrorOffset() const { return errorOffset_; }

	bool parse(const char* filename, generic_value<Encoding>& root)
	{
		std::ifstream fin(filename);
		std::string json;
		std::getline(fin, json, (char)EOF);
		generic_stringstream<Encoding> s(json.c_str());
		return parse(s, root);
	}

	bool parse(Stream& stream, generic_value<Encoding>& root, ParseFlag flag = ParseDefault)
	{
		// comment string "//"
		// /* */
		SkipWhitespace(stream);

		try {
			if (stream.peek() == '\0')
				throw std::runtime_error("Text only contains white space(s).");
			else {
				switch (stream.peek()) {
				case '{':
					root = parseObject(stream, flag);
					break;
				case '[':
					root = parseArray (stream, flag);
					break;
				default:
					throw std::runtime_error("Except either an object or array at root.");
				}

				SkipWhitespace(stream);

				if (stream.peek() != '\0')
					throw std::runtime_error("Nothig should follow the root object or array.");
			}
		} catch (std::exception& e) {
			std::cerr << e.what() << std::endl;
			return false;
		}

		return true;
	}

//private:
	////! Parse JSON text.
	//template <unsigned int Flag, typename Stream, typename Handler>
	//bool parse(Stream& stream, Handler& handler)
	//{
	//	parseError_ = nullptr;
	//	errorOffset_ = 0;
	//	return true;
	//}

	generic_value<Encoding> parseObject(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret(ObjectType);

		assert(stream.peek() == '{');
		stream.take(); // skip '{'
		SkipWhitespace(stream);

		if (stream.peek() == '}') {
			stream.take();
			return ret;
		}

		while(true) {
			if (stream.peek() != '"')
				throw std::runtime_error("Name of an object member must be a string"); // stream.tell();

			generic_value<Encoding> key = parseString(stream, flag);
			SkipWhitespace(stream);

			if (stream.take() != ':')
				throw std::runtime_error("There must be a colon after the name of object member"); // stream.tell();

			SkipWhitespace(stream);

			//generic_value<Encoding> value = parseValue(stream, flag);

			ret.insert(std::move(key), parseValue(stream, flag));

			SkipWhitespace(stream);

			switch (stream.take()) {
			case ',': SkipWhitespace(stream); break;
			case '}': return ret;
			default:
				throw std::runtime_error("Must be a comma or '}' after an object member"); // stream.tell();
			}
		}

		return ret;
	}

	//! Parse array: [ value, ... ]
	generic_value<Encoding> parseArray(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret(ArrayType);

		assert(stream.peek() == '[');
		stream.take(); // skip '['
		SkipWhitespace(stream);

		if (stream.peek() == ']') {
			stream.take();
			return ret;
		}

		while (true) {
			ret.append(parseValue(stream, flag));
			SkipWhitespace(stream);

			switch (stream.take()) {
			case ',':
				SkipWhitespace(stream);
				break;
			case ']':
				return ret;
			default:
				throw std::runtime_error("Must be a comma or ']' after an array member"); // stream.tell();
			}
		}

		return ret;
	}

	generic_value<Encoding> parseNull(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 'n');
		stream.take();

		if (stream.take() == 'u' &&
			stream.take() == 'l' &&
			stream.take() == 'l')
			return generic_value<Encoding>(); // null
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseTrue(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 't');
		stream.take();

		if (stream.take() == 'r' &&
			stream.take() == 'u' &&
			stream.take() == 'e')
			return generic_value<Encoding>(TrueType); // true
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseFalse(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 'f');
		stream.take();

		if (stream.take() == 'a' &&
			stream.take() == 'l' &&
			stream.take() == 's' &&
			stream.take() == 'e')
			return generic_value<Encoding>(FalseType); // false
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseNumber(Stream& stream, ParseFlag flag)
	{
		typedef std::basic_regex<char_type> generic_regex;

		Stream s = stream; // Local copy for optimization

		// parse number
		while ((s.peek() >= '0' && s.peek() <= '9') ||
				s.peek() == '.' ||
				s.peek() == 'e' || s.peek() == 'E' ||
				s.peek() == '-' || s.peek() == '+') s.take();

		/*std::regex re("^(?:-?[0-9]+\\.?[0-9]+([eE][-+]?[0-9]+)?)");
		std::smatch match;
		bool matched = std::regex_match(stream.src_, s.src_, match, re);*/

		generic_value<Encoding> ret(NumberType);

		std::string number(stream.src_, s.src_);

		if (number.find_first_of('.') == std::string::npos)
			ret = std::move(generic_value<Encoding>((natural)std::stoll(number)));
		else
			ret = std::move(generic_value<Encoding>(std::stod(number)));

		stream = s;

		return ret;
	}

	generic_value<Encoding> parseString(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret;
		Stream s = stream;
		assert(s.peek() == '\"');
		s.take(); // skip '\"'

		char_type* head;
		size_type length;

		if (flag & ParseInplace)
			head = s.begin();
		else
			length = 0;

		//bool status = true;
		while (true/*status*/) {
			switch (s.peek()) {
			case '\"':
				// add string
				ret = generic_value<Encoding>(stream.src_ + 1, s.src_); // without '\"'
				s.take();
				stream = s;
				return ret;
			case '\0':
				throw std::runtime_error("Lacks ending quation before the the end of string");
			case '\\':
				throw std::runtime_error("Currently not supported!");
			default:
				s.take(); // normal character
			}
		}

		return ret; // unreachable
	}

	//! Parse any JSON value
	generic_value<Encoding> parseValue(Stream& stream, ParseFlag flag)
	{
		switch (stream.peek()) {
		case 'n': return parseNull  (stream, flag);
		case 't': return parseTrue  (stream, flag);
		case 'f': return parseFalse (stream, flag);
		case '"': return parseString(stream, flag);
		case '{': return parseObject(stream, flag);
		case '[': return parseArray (stream, flag);
		//default:  return parseNumber(stream, flag);
		}

		return parseNumber(stream, flag);
	}
};

//! Reader with UTF8 encoding.
typedef generic_reader<generic_stringstream<UTF8<> >, UTF8<> > Reader;

}<commit_msg>Fix ifstream problem.<commit_after>/**
 *	@file		value.hpp
 *	@author		seonho.oh@gmail.com
 *	@date		2013-11-01
 *	@copyright	2007-2013 seonho.oh@gmail.com, Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
 *	@version	1.0
 */

#pragma once

#include "jsoncxx.hpp"
#include <regex>

namespace jsoncxx
{

///////////////////////////////////////////////////////////////////////////////
// ParseType

//! Combination of parse flag
enum ParseFlag : unsigned int
{
	ParseDefault,	//!< Default parse type. Non-destructive parsing. Text strings are decoded into allocated buffer.
	ParseInplace	//!< Inplace(destructive) parsing.
};

///////////////////////////////////////////////////////////////////////////////
// SkipWhitespace
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
// Version 0.1

//! Skip the JSON white spaces in a stream.
/*! \param stream A input stream for skipping white spaces.
	\note This function has SSE2/SSE4.2 specialization.
*/
template<typename Stream>
void SkipWhitespace(Stream& stream) {
	Stream s = stream;	// Use a local copy for optimization
	while (s.peek() == ' ' || s.peek() == '\n' || s.peek() == '\r' || s.peek() == '\t')
		s.take();
	stream = s;
}

#ifdef JSONCXX_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) {
	static const char whitespace[16] = " \n\r\t";
	__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);

	for (;;) {
		__m128i s = _mm_loadu_si128((const __m128i *)p);
		unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
		if (r == 0)	// all 16 characters are whitespace
			p += 16;
		else {		// some of characters may be non-whitespace
#ifdef _MSC_VER		// Find the index of first non-whitespace
			unsigned long offset;
			if (_BitScanForward(&offset, r))
				return p + offset;
#else
			if (r != 0)
				return p + __builtin_ffs(r) - 1;
#endif
		}
	}
}

#elif defined(JSONCXX_SSE2)

//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) {
	static const char whitespaces[4][17] = {
		"                ",
		"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
		"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};

	__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
	__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
	__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
	__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);

	for (;;) {
		__m128i s = _mm_loadu_si128((const __m128i *)p);
		__m128i x = _mm_cmpeq_epi8(s, w0);
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
		unsigned short r = ~_mm_movemask_epi8(x);
		if (r == 0)	// all 16 characters are whitespace
			p += 16;
		else {		// some of characters may be non-whitespace
#ifdef _MSC_VER		// Find the index of first non-whitespace
			unsigned long offset;
			if (_BitScanForward(&offset, r))
				return p + offset;
#else
			if (r != 0)
				return p + __builtin_ffs(r) - 1;
#endif
		}
	}
}

#endif // JSONCXX_SSE2

#ifdef JSONCXX_SIMD
//! Template function specialization for inplace_stringstream
template<> inline void SkipWhitespace(inplace_stringstream& stream) {
	stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
}

//! Template function specialization for stringstream
template<> inline void SkipWhitespace(stringstream& stream) {
	stream.src_ = SkipWhitespace_SIMD(stream.src_);
}
#endif // JSONCXX_SIMD

template <typename Stream, typename Encoding = UTF8<> >
class generic_reader
{
public:
	typedef typename Encoding::char_type char_type;

	//! ctor
	generic_reader() {}

	//bool hasParseError() const { return parseError_ != nullptr; }
	//const char* getParseError() const { return parseError_; }
	//size_type getErrorOffset() const { return errorOffset_; }

	bool parse(const char* filename, generic_value<Encoding>& root)
	{
		std::ifstream fin(filename);
		if (fin.is_open()) {
			std::string json;
			std::getline(fin, json, (char)EOF);
			generic_stringstream<Encoding> s(json.c_str());
			return parse(s, root);
		}
		return false;
	}

	bool parse(Stream& stream, generic_value<Encoding>& root, ParseFlag flag = ParseDefault)
	{
		// comment string "//"
		// /* */
		SkipWhitespace(stream);

		try {
			if (stream.peek() == '\0')
				throw std::runtime_error("Text only contains white space(s).");
			else {
				switch (stream.peek()) {
				case '{':
					root = parseObject(stream, flag);
					break;
				case '[':
					root = parseArray (stream, flag);
					break;
				default:
					throw std::runtime_error("Except either an object or array at root.");
				}

				SkipWhitespace(stream);

				if (stream.peek() != '\0')
					throw std::runtime_error("Nothig should follow the root object or array.");
			}
		} catch (std::exception& e) {
			std::cerr << e.what() << std::endl;
			return false;
		}

		return true;
	}

//private:
	////! Parse JSON text.
	//template <unsigned int Flag, typename Stream, typename Handler>
	//bool parse(Stream& stream, Handler& handler)
	//{
	//	parseError_ = nullptr;
	//	errorOffset_ = 0;
	//	return true;
	//}

	generic_value<Encoding> parseObject(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret(ObjectType);

		assert(stream.peek() == '{');
		stream.take(); // skip '{'
		SkipWhitespace(stream);

		if (stream.peek() == '}') {
			stream.take();
			return ret;
		}

		while(true) {
			if (stream.peek() != '"')
				throw std::runtime_error("Name of an object member must be a string"); // stream.tell();

			generic_value<Encoding> key = parseString(stream, flag);
			SkipWhitespace(stream);

			if (stream.take() != ':')
				throw std::runtime_error("There must be a colon after the name of object member"); // stream.tell();

			SkipWhitespace(stream);

			//generic_value<Encoding> value = parseValue(stream, flag);

			ret.insert(std::move(key), parseValue(stream, flag));

			SkipWhitespace(stream);

			switch (stream.take()) {
			case ',': SkipWhitespace(stream); break;
			case '}': return ret;
			default:
				throw std::runtime_error("Must be a comma or '}' after an object member"); // stream.tell();
			}
		}

		return ret;
	}

	//! Parse array: [ value, ... ]
	generic_value<Encoding> parseArray(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret(ArrayType);

		assert(stream.peek() == '[');
		stream.take(); // skip '['
		SkipWhitespace(stream);

		if (stream.peek() == ']') {
			stream.take();
			return ret;
		}

		while (true) {
			ret.append(parseValue(stream, flag));
			SkipWhitespace(stream);

			switch (stream.take()) {
			case ',':
				SkipWhitespace(stream);
				break;
			case ']':
				return ret;
			default:
				throw std::runtime_error("Must be a comma or ']' after an array member"); // stream.tell();
			}
		}

		return ret;
	}

	generic_value<Encoding> parseNull(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 'n');
		stream.take();

		if (stream.take() == 'u' &&
			stream.take() == 'l' &&
			stream.take() == 'l')
			return generic_value<Encoding>(); // null
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseTrue(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 't');
		stream.take();

		if (stream.take() == 'r' &&
			stream.take() == 'u' &&
			stream.take() == 'e')
			return generic_value<Encoding>(TrueType); // true
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseFalse(Stream& stream, ParseFlag flag)
	{
		assert(stream.peek() == 'f');
		stream.take();

		if (stream.take() == 'a' &&
			stream.take() == 'l' &&
			stream.take() == 's' &&
			stream.take() == 'e')
			return generic_value<Encoding>(FalseType); // false
		else
			throw std::runtime_error("Invalid value"); // stream.tell() - 1;
	}

	generic_value<Encoding> parseNumber(Stream& stream, ParseFlag flag)
	{
		typedef std::basic_regex<char_type> generic_regex;

		Stream s = stream; // Local copy for optimization

		// parse number
		while ((s.peek() >= '0' && s.peek() <= '9') ||
				s.peek() == '.' ||
				s.peek() == 'e' || s.peek() == 'E' ||
				s.peek() == '-' || s.peek() == '+') s.take();

		/*std::regex re("^(?:-?[0-9]+\\.?[0-9]+([eE][-+]?[0-9]+)?)");
		std::smatch match;
		bool matched = std::regex_match(stream.src_, s.src_, match, re);*/

		generic_value<Encoding> ret(NumberType);

		std::string number(stream.src_, s.src_);

		if (number.find_first_of('.') == std::string::npos)
			ret = std::move(generic_value<Encoding>((natural)std::stoll(number)));
		else
			ret = std::move(generic_value<Encoding>(std::stod(number)));

		stream = s;

		return ret;
	}

	generic_value<Encoding> parseString(Stream& stream, ParseFlag flag)
	{
		generic_value<Encoding> ret;
		Stream s = stream;
		assert(s.peek() == '\"');
		s.take(); // skip '\"'

		char_type* head;
		size_type length;

		if (flag & ParseInplace)
			head = s.begin();
		else
			length = 0;

		//bool status = true;
		while (true/*status*/) {
			switch (s.peek()) {
			case '\"':
				// add string
				ret = generic_value<Encoding>(stream.src_ + 1, s.src_); // without '\"'
				s.take();
				stream = s;
				return ret;
			case '\0':
				throw std::runtime_error("Lacks ending quation before the the end of string");
			case '\\':
				throw std::runtime_error("Currently not supported!");
			default:
				s.take(); // normal character
			}
		}

		return ret; // unreachable
	}

	//! Parse any JSON value
	generic_value<Encoding> parseValue(Stream& stream, ParseFlag flag)
	{
		switch (stream.peek()) {
		case 'n': return parseNull  (stream, flag);
		case 't': return parseTrue  (stream, flag);
		case 'f': return parseFalse (stream, flag);
		case '"': return parseString(stream, flag);
		case '{': return parseObject(stream, flag);
		case '[': return parseArray (stream, flag);
		//default:  return parseNumber(stream, flag);
		}

		return parseNumber(stream, flag);
	}
};

//! Reader with UTF8 encoding.
typedef generic_reader<generic_stringstream<UTF8<> >, UTF8<> > Reader;

}<|endoftext|>


<commit_before>/*
 * Only 16 bit PCM MONO supported now.
 */
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#define BUFFERSIZE 1 // Number of sample rates (ex. seconds)
#define MINWAVEFREQ 20 // Minimum frequency that we want to process

using namespace std;
bool check_sample(const char*, const char*);
FILE * process_headers(const char*);
void dump_values(FILE * in);
void read_periods(const char*);
void read_cfg(const char*);
void fatal (const char* );

char errmsg[200]; // Temporary message
int SAMPLE_RATE, //
	DATA_SIZE,  // Data chunk size in bytes
	PROC_SAMPLES; // Minimum number of samples to process and be sure two waves included

map<string, string> cfg; // OK, ok... Is it possible to store any value but string (Rrrr...) here?

struct trange {
	double tmin; double tm; double tmax;
};
struct tworkitm {
	int found; trange r;
};

typedef map<int, tworkitm> twork;

int main (int argc, char *argv[]) {
    if (argc < 2) {
        fatal ("Unspecified config file. exiting\n");
    }
	read_cfg(argv[1]);
	// ------------------------------------------------------------
	// Only header given, we just dump out the silence values
	//
	if (argc == 2) {
		FILE * in = process_headers(cfg["filename"].c_str());
		dump_values(in);
	}
	// ------------------------------------------------------------
	// We have values file and a new samplefile. Let's rock
	//
	else if (argc == 4) {
		vector<pair<double,trange> > vals;
		twork work;

		ifstream file;
		file.open(argv[2]);
		string line;
		int x;
		while (! file.eof() ) {
			getline(file, line);
			x = line.find(";");
			if (x == -1) break;
			istringstream i(line.substr(0,x));
			istringstream j(line.substr(x+1));

			pair<double,trange> tmp;
			i >> tmp.first;
			j >> tmp.second.tm;
			tmp.second.tmin = tmp.second.tm * 0.9;
			tmp.second.tmax = tmp.second.tm * 1.1;
			vals.insert(vals.end(), tmp);
		}
		// OK, we have it. Let's print?
		//for (vector<trange>::iterator it1 = vals.begin(); it1 != vals.end(); it1++) {
			//printf ("%.6f - %.6f\n", (*it1).first, (*it1).second);
		//}
		// ------------------------------------------------------------
		// Let's work with the seconds sample like with a stream
		//
		FILE * an = process_headers(argv[3]);
		// We can read and analyze it now
		// Trying to match in only first 15 seconds of the record

		short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
		istringstream i(cfg["treshold1"]);
		double treshold1;
		i >> treshold1;
		int min_silence = (int)((1 << 15) * treshold1), // Below this value we have "silence, pshhh..."
			found_s = 0,
			head = 0;
		while (! feof(an) ) {
			fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, an);
			for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
				int cur = abs(buf[i]);

				if (cur <= min_silence) {
					found_s++;
				} else {
					if (found_s >= PROC_SAMPLES) {
						// Found a found_s/SAMPLE_RATE length silence
						// Let's look for an analogous thing in vals variable (original file)
						double sec = (double)found_s / SAMPLE_RATE;
						bool found = false;
						for (int i = 0; i < vals.size(); i++) {
							if (vals[i].second.tmin < sec && sec < vals[i].second.tmax) {
								found = true;
								// Found a matching duration
								/*
								printf("%7.4f<->%7.4f,     %.4f<->%.4f (%5.2f%%)\n",
										vals[i].first, (double)(head-found_s)/SAMPLE_RATE,
										vals[i].second.tm, sec,
										vals[i].second.tm *100/sec-100);
										*/
								// Check if it exists in our work array (by next number)
								twork::iterator f = work.find(i+1);
								if (f == work.end()) { // Not found, insert new elem.
									tworkitm tmp;
									tmp.found = 1;
									tmp.r = vals[i+1].second;
									work[i+1] = tmp;
								}
								else {
									// We were waiting for this value! Lucky ;)
									work[i+1].found++;
									printf ("Incremented! to %d!\n", work[i+1].found);
								}
							}
						}
						if (!found) { // Found a silence, but could not find any matching element
							work.clear();
						}
					}
					found_s = 0;
				}
				head++;
			}
		}
	}
    exit(0);
}

void read_cfg (const char * filename) {
	ifstream file;
	file.open(filename);
	string line;
	int x;
	while (! file.eof() ) {
		getline(file, line);
		x = line.find(":");
		if (x == -1) break; // Last line, exit
		cfg[line.substr(0,x)] = line.substr(x+2);
	}
}

FILE * process_headers(const char * infile) {
    FILE * in = fopen(infile, "rb");

    // Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
    char header[5];
    fread(header, 1, 4, in);

    char sample[] = "RIFF";
    if (! check_sample(sample, header) ) {
        fatal ("RIFF header not found, exiting\n");
    }
	// Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
	short int tmp[2]; // two-byte integer
	fseek(in, 0x14, 0); // offset = 20 bytes
    fread(&tmp, 2, 2, in); // Reading two two-byte samples (comp. code and no. of channels)
    if ( tmp[0] != 1 ) {
		sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
		fatal (errmsg);
    }
	// Number of channels must be "MONO"
    if ( tmp[1] != 1 ) {
		printf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
		fatal (errmsg);
    }
	fread(&SAMPLE_RATE, 2, 1, in); // Single two-byte sample
	//printf ("Sample rate: %d\n", SAMPLE_RATE);
	PROC_SAMPLES = SAMPLE_RATE / MINWAVEFREQ;
	fseek(in, 0x24, 0);
	fread(header, 1, 4, in);
	strcpy(sample, "data");
	if (! check_sample(sample, header)) {
		fatal ("data chunk not found in byte offset=36, file corrupted.");
	}
    // Get data chunk size here
	fread(&DATA_SIZE, 4, 1, in); // Single two-byte sample
    //printf ("Datasize: %d bytes\n", DATA_SIZE);
	return in;
}

bool check_sample (const char * sample, const char * b) { // My STRCPY.
    for(int i = 0; i < sizeof(sample)-1; i++) {
        if (sample[i] != b[i]) {
            return false;
        }
    }
    return true;
}

void fatal (const char * msg) { // Print error message and exit
    perror (msg);
    exit (1);
}

void dump_values(FILE * in) {
	istringstream i(cfg["treshold1"]);
	double treshold1;
	i >> treshold1;
	// ------------------------------------------------------------
	// This "15" means we have 16 bits for signed, this means
	// 15 bits for unsigned int.
	int min_silence = (int)((1 << 15) * treshold1); // Below this value we have "silence, pshhh..."

    short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
	int head = 0, // Assume sample started
		found_s = 0; // Number of silence samples

	int first_silence = 0;

    while (! feof(in) ) {
        fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, in);
        for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
			int cur = abs(buf[i]);

			if (cur <= min_silence) {
				found_s++;
			} else {
				if (found_s >= PROC_SAMPLES) {
					printf("%.6f;%.6f\n", (double)(head-found_s)/SAMPLE_RATE, (double)found_s/SAMPLE_RATE);
				}
				found_s = 0;
			}
			head++;
        }
    }
}
<commit_msg>Added "range" class<commit_after>/*
 * Only 16 bit PCM MONO supported now.
 */
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#define BUFFERSIZE 1 // Number of sample rates (ex. seconds)
#define MINWAVEFREQ 20 // Minimum frequency that we want to process

using namespace std;
bool check_sample(const char*, const char*);
FILE * process_headers(const char*);
void dump_values(FILE * in);
void read_periods(const char*);
void read_cfg(const char*);
void fatal (const char* );

char errmsg[200]; // Temporary message
int SAMPLE_RATE, //
	DATA_SIZE,  // Data chunk size in bytes
	PROC_SAMPLES; // Minimum number of samples to process and be sure two waves included

map<string, string> cfg; // OK, ok... Is it possible to store any value but string (Rrrr...) here?

class Range {
	public:
		Range() { tm = tmin = tmax = 0; };
		Range(const double & a) { tm = a; tmin = a * 0.9; tmax = a * 1.1; }
		Range operator = (const double i) { return Range(i); }
		bool operator == (const double & i) const { return tmin < i && i < tmax; }
		bool operator == (const Range & r) const { return r == tm; }
		bool operator > (const double & i) const { return i > tmax; }
		bool operator > (const Range & r) const { return r > tm; }
		bool operator < (const double & i) const { return i < tmin; }
		bool operator < (const Range & r) const { return r < tm; }
	protected:
		int tmin, tm, tmax;
};

struct tworkitm {
	int found; Range r;
};

typedef map<int, tworkitm> twork;
typedef multimap<Range,pair<int,double> > tvals;

int main (int argc, char *argv[]) {

    if (argc < 2) {
        fatal ("Unspecified config file. exiting\n");
    }
	read_cfg(argv[1]);
	// ------------------------------------------------------------
	// Only header given, we just dump out the silence values
	//
	if (argc == 2) {
		FILE * in = process_headers(cfg["filename"].c_str());
		dump_values(in);
	}
	// ------------------------------------------------------------
	// We have values file and a new samplefile. Let's rock
	//
	else if (argc == 4) {
		tvals vals;
		twork work;

		ifstream file;
		file.open(argv[2]);
		string line;
		int x;
		double tmp2;
		for (int i = 0; ! file.eof(); i++) {
			getline(file, line);
			x = line.find(";");
			if (x == -1) break;
			istringstream place(line.substr(0,x));
			istringstream range(line.substr(x+1));
			pair<Range,pair<int,double> > tmp;
			range >> tmp2;
			tmp.first = tmp2;
			place >> tmp.second.second;
			tmp.second.first = i;
			vals.insert(tmp);
		}
		// OK, we have it. Let's print?
		//for (vector<trange>::iterator it1 = vals.begin(); it1 != vals.end(); it1++) {
			//printf ("%.6f - %.6f\n", (*it1).first, (*it1).second);
		//}
		// ------------------------------------------------------------
		// Let's work with the seconds sample like with a stream
		//
		FILE * an = process_headers(argv[3]);
		// We can read and analyze it now
		// Trying to match in only first 15 seconds of the record

		short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
		istringstream i(cfg["treshold1"]);
		double treshold1;
		i >> treshold1;
		int min_silence = (int)((1 << 15) * treshold1), // Below this value we have "silence, pshhh..."
			found_s = 0,
			head = 0;
		while (! feof(an) ) {
			fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, an);
			for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
				int cur = abs(buf[i]);

				if (cur <= min_silence) {
					found_s++;
				} else {
					if (found_s >= PROC_SAMPLES) {
						// Found a found_s/SAMPLE_RATE length silence
						// Let's look for an analogous thing in vals variable (original file)
						double sec = (double)found_s/SAMPLE_RATE;
						// Find sec in range
						pair<tvals::iterator, tvals::iterator> pa = vals.equal_range(sec);

						if (pa.first == pa.second) {
							// Silence of that length not found in vals
							work.clear();
						}
						else
						{
							for (tvals::iterator it1 = pa.first; it1 != pa.second; it1++)
							{
								// Found a matching duration
								int i = (*it1).second.first; // Position in our array
								/*
								printf("%7.4f<->%7.4f,     %.4f<->%.4f (%5.2f%%)\n",
										vals[i].first, (double)(head-found_s)/SAMPLE_RATE,
										vals[i].second.tm, sec,
										vals[i].second.tm *100/sec-100);
										*/
								// Check if it exists in our work array (by next number)
								twork::iterator f = work.find(i+1);
								if (f == work.end()) { // Not found, insert new elem.
									tworkitm tmp;
									tmp.found = 1;
									tvals::iterator it2 = it1;
									it2++;
									tmp.r = (*it2).first;
									work[i+1] = tmp;
								}
								else {
									// We were waiting for this value! Lucky ;)
									work[i+1].found++;
									printf ("Incremented! to %d!\n", work[i+1].found);
								}
							}
						}
						// Looking for another silence
						found_s = 0;
					}
				}
				head++;
			}
		}
	}
    exit(0);
}

void read_cfg (const char * filename) {
	ifstream file;
	file.open(filename);
	string line;
	int x;
	while (! file.eof() ) {
		getline(file, line);
		x = line.find(":");
		if (x == -1) break; // Last line, exit
		cfg[line.substr(0,x)] = line.substr(x+2);
	}
}

FILE * process_headers(const char * infile) {
    FILE * in = fopen(infile, "rb");

    // Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
    char header[5];
    fread(header, 1, 4, in);

    char sample[] = "RIFF";
    if (! check_sample(sample, header) ) {
        fatal ("RIFF header not found, exiting\n");
    }
	// Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
	short int tmp[2]; // two-byte integer
	fseek(in, 0x14, 0); // offset = 20 bytes
    fread(&tmp, 2, 2, in); // Reading two two-byte samples (comp. code and no. of channels)
    if ( tmp[0] != 1 ) {
		sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
		fatal (errmsg);
    }
	// Number of channels must be "MONO"
    if ( tmp[1] != 1 ) {
		printf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
		fatal (errmsg);
    }
	fread(&SAMPLE_RATE, 2, 1, in); // Single two-byte sample
	//printf ("Sample rate: %d\n", SAMPLE_RATE);
	PROC_SAMPLES = SAMPLE_RATE / MINWAVEFREQ;
	fseek(in, 0x24, 0);
	fread(header, 1, 4, in);
	strcpy(sample, "data");
	if (! check_sample(sample, header)) {
		fatal ("data chunk not found in byte offset=36, file corrupted.");
	}
    // Get data chunk size here
	fread(&DATA_SIZE, 4, 1, in); // Single two-byte sample
    //printf ("Datasize: %d bytes\n", DATA_SIZE);
	return in;
}

bool check_sample (const char * sample, const char * b) { // My STRCPY.
    for(int i = 0; i < sizeof(sample)-1; i++) {
        if (sample[i] != b[i]) {
            return false;
        }
    }
    return true;
}

void fatal (const char * msg) { // Print error message and exit
    perror (msg);
    exit (1);
}

void dump_values(FILE * in) {
	istringstream i(cfg["treshold1"]);
	double treshold1;
	i >> treshold1;
	// ------------------------------------------------------------
	// This "15" means we have 16 bits for signed, this means
	// 15 bits for unsigned int.
	int min_silence = (int)((1 << 15) * treshold1); // Below this value we have "silence, pshhh..."

    short int buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every second
	int head = 0, // Assume sample started
		found_s = 0; // Number of silence samples

	int first_silence = 0;

    while (! feof(in) ) {
        fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, in);
        for (int i = 0; i < SAMPLE_RATE * BUFFERSIZE; i++) {
			int cur = abs(buf[i]);

			if (cur <= min_silence) {
				found_s++;
			} else {
				if (found_s >= PROC_SAMPLES) {
					printf("%.6f;%.6f\n", (double)(head-found_s)/SAMPLE_RATE, (double)found_s/SAMPLE_RATE);
				}
				found_s = 0;
			}
			head++;
        }
    }
}
<|endoftext|>


<commit_before>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/
#include "glc_ext.h"
#include <QString>

// Define glcGetProcAddress.
#if defined(Q_OS_WIN32)
#	define glcGetProcAddress(name) wglGetProcAddress((LPCSTR)name)
#else
#	if defined(Q_OS_MAC)
#   	define glcGetProcAddress(name) NSGLGetProcAddress(name)
#	else
#		if defined(Q_OS_LINUX)
#			define glcGetProcAddress(name) (*glXGetProcAddressARB)(name)
#		endif
#	endif
#endif

#if !defined(Q_OS_MAC)
// ARB_vertex_buffer_object
PFNGLBINDBUFFERARBPROC				glBindBuffer			= NULL;
PFNGLDELETEBUFFERSARBPROC			glDeleteBuffers			= NULL;
PFNGLGENBUFFERSARBPROC				glGenBuffers			= NULL;
PFNGLISBUFFERARBPROC				glIsBuffer				= NULL;
PFNGLBUFFERDATAARBPROC				glBufferData			= NULL;
PFNGLBUFFERSUBDATAARBPROC			glBufferSubData			= NULL;
PFNGLGETBUFFERSUBDATAARBPROC		glGetBufferSubData		= NULL;
PFNGLMAPBUFFERARBPROC				glMapBuffer				= NULL;
PFNGLUNMAPBUFFERARBPROC				glUnmapBuffer			= NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameteriv	= NULL;
PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointerv		= NULL;
// glDrawRangElement
PFNGLDRAWRANGEELEMENTSPROC 			glDrawRangeElements		= NULL;

// GL_ARB_shader_objects
PFNGLCREATEPROGRAMOBJECTARBPROC		glCreateProgram			= NULL;
PFNGLDELETEPROGRAMPROC				glDeleteProgram			= NULL;
PFNGLUSEPROGRAMOBJECTARBPROC		glUseProgram			= NULL;
PFNGLCREATESHADEROBJECTARBPROC		glCreateShader			= NULL;
PFNGLDELETESHADERPROC				glDeleteShader			= NULL;
PFNGLSHADERSOURCEARBPROC			glShaderSource			= NULL;
PFNGLCOMPILESHADERARBPROC			glCompileShader			= NULL;
PFNGLATTACHOBJECTARBPROC			glAttachShader			= NULL;
PFNGLDETACHOBJECTARBPROC			glDetachShader			= NULL;
PFNGLLINKPROGRAMARBPROC				glLinkProgram			= NULL;
PFNGLGETUNIFORMLOCATIONARBPROC		glGetUniformLocation	= NULL;
PFNGLUNIFORM4FARBPROC				glUniform4f				= NULL;
PFNGLUNIFORM1IARBPROC				glUniform1i				= NULL;
PFNGLGETSHADERIVPROC				glGetShaderiv			= NULL;
PFNGLGETPROGRAMIVARBPROC			glGetProgramiv			= NULL;
PFNGLISPROGRAMARBPROC				glIsProgram				= NULL;
#endif

//const QString glExtension(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));

// Return true if the extension is supported
bool glc::extensionIsSupported(const QString& extension)
{
	QString glExtension(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
	return glExtension.contains(extension);
}

// Return true if VBO extension is succesfully loaded
bool glc::loadVboExtension()
{
	bool result= true;
#if !defined(Q_OS_MAC)
    glBindBuffer				= (PFNGLBINDBUFFERARBPROC)glcGetProcAddress("glBindBuffer");
    glDeleteBuffers				= (PFNGLDELETEBUFFERSARBPROC)glcGetProcAddress("glDeleteBuffers");
    glGenBuffers				= (PFNGLGENBUFFERSARBPROC)glcGetProcAddress("glGenBuffers");
    glIsBuffer					= (PFNGLISBUFFERARBPROC)glcGetProcAddress("glIsBuffer");
    glBufferData				= (PFNGLBUFFERDATAARBPROC)glcGetProcAddress("glBufferData");
    glBufferSubData				= (PFNGLBUFFERSUBDATAARBPROC)glcGetProcAddress("glBufferSubData");
    glGetBufferSubData			= (PFNGLGETBUFFERSUBDATAARBPROC)glcGetProcAddress("glGetBufferSubData");
    glMapBuffer					= (PFNGLMAPBUFFERARBPROC)glcGetProcAddress("glMapBuffer");
    glUnmapBuffer				= (PFNGLUNMAPBUFFERARBPROC)glcGetProcAddress("glUnmapBuffer");
    glGetBufferParameteriv		= (PFNGLGETBUFFERPARAMETERIVARBPROC)glcGetProcAddress("glGetBufferParameteriv");
    glGetBufferPointerv			= (PFNGLGETBUFFERPOINTERVARBPROC)glcGetProcAddress("glGetBufferPointerv");
    glDrawRangeElements			= (PFNGLDRAWRANGEELEMENTSPROC)glcGetProcAddress("glDrawRangeElements");

    result= glBindBuffer and glDeleteBuffers and glGenBuffers and glIsBuffer and glBufferData and glBufferSubData and
    glGetBufferSubData and glMapBuffer and glUnmapBuffer and glGetBufferParameteriv and glGetBufferPointerv and glDrawRangeElements;
#endif
    return result;

}

// Load GLSL extensions
bool glc::loadGlSlExtension()
{
	bool result= true;
#if !defined(Q_OS_MAC)
	glCreateProgram				= (PFNGLCREATEPROGRAMOBJECTARBPROC)glcGetProcAddress("glCreateProgram");
	if (not glCreateProgram) qDebug() << "not glCreateProgram";
	glDeleteProgram 			= (PFNGLDELETEPROGRAMPROC)glcGetProcAddress("glDeleteProgram");
	if (not glDeleteProgram) qDebug() << "not glDeleteProgram";
	glUseProgram				= (PFNGLUSEPROGRAMOBJECTARBPROC)glcGetProcAddress("glUseProgram");
	if (not glUseProgram) qDebug() << "not glUseProgram";
	glCreateShader				= (PFNGLCREATESHADEROBJECTARBPROC)glcGetProcAddress("glCreateShader");
	if (not glCreateShader) qDebug() << "not glCreateShader";
	glDeleteShader				= (PFNGLDELETESHADERPROC)glcGetProcAddress("glDeleteShader");
	if (not glDeleteShader) qDebug() << "not glDeleteShader";
	glShaderSource				= (PFNGLSHADERSOURCEARBPROC)glcGetProcAddress("glShaderSource");
	if (not glShaderSource) qDebug() << "not glShaderSource";
	glCompileShader				= (PFNGLCOMPILESHADERARBPROC)glcGetProcAddress("glCompileShader");
	if (not glCompileShader) qDebug() << "not glCompileShader";
	glAttachShader				= (PFNGLATTACHOBJECTARBPROC)glcGetProcAddress("glAttachShader");
	if (not glAttachShader) qDebug() << "not glAttachShader";
	glDetachShader				= (PFNGLDETACHOBJECTARBPROC)glcGetProcAddress("glDetachShader");
	if (not glDetachShader) qDebug() << "not glDetachShader";
	glLinkProgram				= (PFNGLLINKPROGRAMARBPROC)glcGetProcAddress("glLinkProgram");
	if (not glLinkProgram) qDebug() << "not glLinkProgram";
	glGetUniformLocation		= (PFNGLGETUNIFORMLOCATIONARBPROC)glcGetProcAddress("glGetUniformLocation");
	if (not glGetUniformLocation) qDebug() << "not glGetUniformLocation";
	glUniform4f					= (PFNGLUNIFORM4FARBPROC)glcGetProcAddress("glUniform4f");
	if (not glUniform4f) qDebug() << "not glUniform4f";
	glUniform1i					= (PFNGLUNIFORM1IARBPROC)glcGetProcAddress("glUniform1i");
	if (not glUniform1i) qDebug() << "not glUniform1i";
	glGetShaderiv				= (PFNGLGETSHADERIVPROC)glcGetProcAddress("glGetShaderiv");
	if (not glGetShaderiv) qDebug() << "not glGetShaderiv";
	glGetProgramiv				= (PFNGLGETPROGRAMIVARBPROC)glcGetProcAddress("glGetProgramiv");
	if (not glGetProgramiv) qDebug() << "not glGetProgramiv";
	glIsProgram					= (PFNGLISPROGRAMARBPROC)glcGetProcAddress("glIsProgram");

	result= glCreateProgram and glDeleteProgram and glUseProgram and glCreateShader and glDeleteShader and
    glShaderSource and glCompileShader and glAttachShader and glDetachShader and glLinkProgram and
    glGetUniformLocation and glUniform4f and glUniform1i and glGetShaderiv and glGetProgramiv and glIsProgram;

#endif
    return result;
}

<commit_msg>Use the QT getProcAdress Function.<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/
#include "glc_ext.h"
#include <QString>
#include <QGLContext>
#include <QDebug>

#if !defined(Q_OS_MAC)
// ARB_vertex_buffer_object
PFNGLBINDBUFFERARBPROC				glBindBuffer			= NULL;
PFNGLDELETEBUFFERSARBPROC			glDeleteBuffers			= NULL;
PFNGLGENBUFFERSARBPROC				glGenBuffers			= NULL;
PFNGLISBUFFERARBPROC				glIsBuffer				= NULL;
PFNGLBUFFERDATAARBPROC				glBufferData			= NULL;
PFNGLBUFFERSUBDATAARBPROC			glBufferSubData			= NULL;
PFNGLGETBUFFERSUBDATAARBPROC		glGetBufferSubData		= NULL;
PFNGLMAPBUFFERARBPROC				glMapBuffer				= NULL;
PFNGLUNMAPBUFFERARBPROC				glUnmapBuffer			= NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameteriv	= NULL;
PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointerv		= NULL;
// glDrawRangElement
PFNGLDRAWRANGEELEMENTSPROC 			glDrawRangeElements		= NULL;

// GL_ARB_shader_objects
PFNGLCREATEPROGRAMOBJECTARBPROC		glCreateProgram			= NULL;
PFNGLDELETEPROGRAMPROC				glDeleteProgram			= NULL;
PFNGLUSEPROGRAMOBJECTARBPROC		glUseProgram			= NULL;
PFNGLCREATESHADEROBJECTARBPROC		glCreateShader			= NULL;
PFNGLDELETESHADERPROC				glDeleteShader			= NULL;
PFNGLSHADERSOURCEARBPROC			glShaderSource			= NULL;
PFNGLCOMPILESHADERARBPROC			glCompileShader			= NULL;
PFNGLATTACHOBJECTARBPROC			glAttachShader			= NULL;
PFNGLDETACHOBJECTARBPROC			glDetachShader			= NULL;
PFNGLLINKPROGRAMARBPROC				glLinkProgram			= NULL;
PFNGLGETUNIFORMLOCATIONARBPROC		glGetUniformLocation	= NULL;
PFNGLUNIFORM4FARBPROC				glUniform4f				= NULL;
PFNGLUNIFORM1IARBPROC				glUniform1i				= NULL;
PFNGLGETSHADERIVPROC				glGetShaderiv			= NULL;
PFNGLGETPROGRAMIVARBPROC			glGetProgramiv			= NULL;
PFNGLISPROGRAMARBPROC				glIsProgram				= NULL;
#endif

//const QString glExtension(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));

// Return true if the extension is supported
bool glc::extensionIsSupported(const QString& extension)
{
	QString glExtension(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
	return glExtension.contains(extension);
}

// Return true if VBO extension is succesfully loaded
bool glc::loadVboExtension()
{
	bool result= true;
#if !defined(Q_OS_MAC)
	const QGLContext* pContext= QGLContext::currentContext();
    glBindBuffer				= (PFNGLBINDBUFFERARBPROC)pContext->getProcAddress(QLatin1String("glBindBuffer"));
    glDeleteBuffers				= (PFNGLDELETEBUFFERSARBPROC)pContext->getProcAddress(QLatin1String("glDeleteBuffers"));
    glGenBuffers				= (PFNGLGENBUFFERSARBPROC)pContext->getProcAddress(QLatin1String("glGenBuffers"));
    glIsBuffer					= (PFNGLISBUFFERARBPROC)pContext->getProcAddress(QLatin1String("glIsBuffer"));
    glBufferData				= (PFNGLBUFFERDATAARBPROC)pContext->getProcAddress(QLatin1String("glBufferData"));
    glBufferSubData				= (PFNGLBUFFERSUBDATAARBPROC)pContext->getProcAddress(QLatin1String("glBufferSubData"));
    glGetBufferSubData			= (PFNGLGETBUFFERSUBDATAARBPROC)pContext->getProcAddress(QLatin1String("glGetBufferSubData"));
    glMapBuffer					= (PFNGLMAPBUFFERARBPROC)pContext->getProcAddress(QLatin1String("glMapBuffer"));
    glUnmapBuffer				= (PFNGLUNMAPBUFFERARBPROC)pContext->getProcAddress(QLatin1String("glUnmapBuffer"));
    glGetBufferParameteriv		= (PFNGLGETBUFFERPARAMETERIVARBPROC)pContext->getProcAddress(QLatin1String("glGetBufferParameteriv"));
    glGetBufferPointerv			= (PFNGLGETBUFFERPOINTERVARBPROC)pContext->getProcAddress(QLatin1String("glGetBufferPointerv"));
    glDrawRangeElements			= (PFNGLDRAWRANGEELEMENTSPROC)pContext->getProcAddress(QLatin1String("glDrawRangeElements"));

    result= glBindBuffer and glDeleteBuffers and glGenBuffers and glIsBuffer and glBufferData and glBufferSubData and
    glGetBufferSubData and glMapBuffer and glUnmapBuffer and glGetBufferParameteriv and glGetBufferPointerv and glDrawRangeElements;
#endif
    return result;

}

// Load GLSL extensions
bool glc::loadGlSlExtension()
{
	bool result= true;
#if !defined(Q_OS_MAC)
	const QGLContext* pContext= QGLContext::currentContext();
	glCreateProgram				= (PFNGLCREATEPROGRAMOBJECTARBPROC)pContext->getProcAddress(QLatin1String("glCreateProgram"));
	if (not glCreateProgram) qDebug() << "not glCreateProgram";
	glDeleteProgram 			= (PFNGLDELETEPROGRAMPROC)pContext->getProcAddress(QLatin1String("glDeleteProgram"));
	if (not glDeleteProgram) qDebug() << "not glDeleteProgram";
	glUseProgram				= (PFNGLUSEPROGRAMOBJECTARBPROC)pContext->getProcAddress(QLatin1String("glUseProgram"));
	if (not glUseProgram) qDebug() << "not glUseProgram";
	glCreateShader				= (PFNGLCREATESHADEROBJECTARBPROC)pContext->getProcAddress(QLatin1String("glCreateShader"));
	if (not glCreateShader) qDebug() << "not glCreateShader";
	glDeleteShader				= (PFNGLDELETESHADERPROC)pContext->getProcAddress(QLatin1String("glDeleteShader"));
	if (not glDeleteShader) qDebug() << "not glDeleteShader";
	glShaderSource				= (PFNGLSHADERSOURCEARBPROC)pContext->getProcAddress(QLatin1String("glShaderSource"));
	if (not glShaderSource) qDebug() << "not glShaderSource";
	glCompileShader				= (PFNGLCOMPILESHADERARBPROC)pContext->getProcAddress(QLatin1String("glCompileShader"));
	if (not glCompileShader) qDebug() << "not glCompileShader";
	glAttachShader				= (PFNGLATTACHOBJECTARBPROC)pContext->getProcAddress(QLatin1String("glAttachShader"));
	if (not glAttachShader) qDebug() << "not glAttachShader";
	glDetachShader				= (PFNGLDETACHOBJECTARBPROC)pContext->getProcAddress(QLatin1String("glDetachShader"));
	if (not glDetachShader) qDebug() << "not glDetachShader";
	glLinkProgram				= (PFNGLLINKPROGRAMARBPROC)pContext->getProcAddress(QLatin1String("glLinkProgram"));
	if (not glLinkProgram) qDebug() << "not glLinkProgram";
	glGetUniformLocation		= (PFNGLGETUNIFORMLOCATIONARBPROC)pContext->getProcAddress(QLatin1String("glGetUniformLocation"));
	if (not glGetUniformLocation) qDebug() << "not glGetUniformLocation";
	glUniform4f					= (PFNGLUNIFORM4FARBPROC)pContext->getProcAddress(QLatin1String("glUniform4f"));
	if (not glUniform4f) qDebug() << "not glUniform4f";
	glUniform1i					= (PFNGLUNIFORM1IARBPROC)pContext->getProcAddress(QLatin1String("glUniform1i"));
	if (not glUniform1i) qDebug() << "not glUniform1i";
	glGetShaderiv				= (PFNGLGETSHADERIVPROC)pContext->getProcAddress(QLatin1String("glGetShaderiv"));
	if (not glGetShaderiv) qDebug() << "not glGetShaderiv";
	glGetProgramiv				= (PFNGLGETPROGRAMIVARBPROC)pContext->getProcAddress(QLatin1String("glGetProgramiv"));
	if (not glGetProgramiv) qDebug() << "not glGetProgramiv";
	glIsProgram					= (PFNGLISPROGRAMARBPROC)pContext->getProcAddress(QLatin1String("glIsProgram"));

	result= glCreateProgram and glDeleteProgram and glUseProgram and glCreateShader and glDeleteShader and
    glShaderSource and glCompileShader and glAttachShader and glDetachShader and glLinkProgram and
    glGetUniformLocation and glUniform4f and glUniform1i and glGetShaderiv and glGetProgramiv and glIsProgram;

#endif
    return result;
}

<|endoftext|>