#ifndef SPROUT_COMPOST_EFFECTS_CHORUS_HPP #define SPROUT_COMPOST_EFFECTS_CHORUS_HPP #include #include #include #include #include #include #include #include #include #include namespace sprout { namespace compost { // // chorus_outdirected_value // template struct chorus_outdirected_value { public: typedef Value value_type; typedef IntType int_type; private: value_type d_; value_type depth_; value_type rate_; int_type samples_per_sec_; private: template SPROUT_CONSTEXPR typename std::iterator_traits::value_type calc_2(Outdirected const& x, typename Outdirected::index_type m, value_type const& delta) const { return *x + (m >= 0 && (m + 1 < x.base().get() || x.base().get() < 0) ? delta * x[m + 1 - x.index()] + (1 - delta) * x[m - x.index()] : 0 ) ; } template SPROUT_CONSTEXPR typename std::iterator_traits::value_type calc_1(Outdirected const& x, value_type const& tau, value_type const& t) const { return calc_2(x, static_cast(t), t - static_cast(t)); } template SPROUT_CONSTEXPR typename std::iterator_traits::value_type calc(Outdirected const& x, value_type const& tau) const { return calc_1(x, tau, x.index() - tau); } public: SPROUT_CONSTEXPR chorus_outdirected_value( value_type const& d, value_type const& depth, value_type const& rate, int_type samples_per_sec = 44100 ) : d_(d), depth_(depth), rate_(rate), samples_per_sec_(samples_per_sec) {} template SPROUT_CONSTEXPR typename std::iterator_traits::value_type operator()(Outdirected const& x) const { return calc(x, d_ + depth_ * sprout::sin(sprout::math::two_pi() * rate_ * x.index() / samples_per_sec_)); } }; namespace effects { // // chorus_holder // template class chorus_holder { public: typedef T value_type; typedef IntType int_type; private: value_type d_; value_type depth_; value_type rate_; int_type samples_per_sec_; public: chorus_holder() = default; chorus_holder(chorus_holder const&) = default; SPROUT_CONSTEXPR chorus_holder( value_type const& d, value_type const& depth, value_type const& rate, int_type samples_per_sec = 44100 ) : d_(d), depth_(depth), rate_(rate), samples_per_sec_(samples_per_sec) {} SPROUT_CONSTEXPR value_type const& d() const { return d_; } SPROUT_CONSTEXPR value_type const& depth() const { return depth_; } SPROUT_CONSTEXPR value_type const& rate() const { return rate_; } SPROUT_CONSTEXPR int_type const& samples_per_sec() const { return samples_per_sec_; } }; // // chorus_forwarder // class chorus_forwarder { public: template SPROUT_CONSTEXPR sprout::compost::effects::chorus_holder operator()(T const& d, T const& depth, T const& rate, IntType samples_per_sec) const { return sprout::compost::effects::chorus_holder(d, depth, rate, samples_per_sec); } template SPROUT_CONSTEXPR sprout::compost::effects::chorus_holder operator()(T const& d, T const& depth, T const& rate) const { return sprout::compost::effects::chorus_holder(d, depth, rate); } }; // // chorus // namespace { SPROUT_STATIC_CONSTEXPR sprout::compost::effects::chorus_forwarder chorus = {}; } // anonymous-namespace // // operator| // template inline SPROUT_CONSTEXPR auto operator|(Range&& lhs, sprout::compost::effects::chorus_holder const& rhs) -> decltype( sprout::forward(lhs) | sprout::adaptors::valued(sprout::size(sprout::forward(lhs))) | sprout::adaptors::indexed | sprout::adaptors::outdirected | sprout::adaptors::transformed( sprout::compost::chorus_outdirected_value( rhs.d(), rhs.depth(), rhs.rate(), rhs.samples_per_sec() ) ) ) { return sprout::forward(lhs) | sprout::adaptors::valued(sprout::size(sprout::forward(lhs))) | sprout::adaptors::indexed | sprout::adaptors::outdirected | sprout::adaptors::transformed( sprout::compost::chorus_outdirected_value( rhs.d(), rhs.depth(), rhs.rate(), rhs.samples_per_sec() ) ) ; } } // namespace effects using sprout::compost::effects::chorus; } // namespace compost } // namespace sprout #endif // #ifndef SPROUT_COMPOST_EFFECTS_CHORUS_HPP