15static constexpr int BLIP_IMPULSE_WIDTH = 16;
22static constexpr auto impulses = [] {
23 constexpr int HALF_SIZE = BLIP_RES / 2 * (BLIP_IMPULSE_WIDTH - 1);
24 std::array<double, BLIP_RES + HALF_SIZE + BLIP_RES> fImpulse = {};
25 std::span<double, HALF_SIZE> out = subspan<HALF_SIZE>(fImpulse, BLIP_RES);
26 std::span<double, BLIP_RES>
end = subspan<BLIP_RES >(fImpulse, BLIP_RES + HALF_SIZE);
29 double overSample = ((4.5 / (BLIP_IMPULSE_WIDTH - 1)) + 0.85);
30 double to_angle =
Math::pi / (2.0 * overSample * BLIP_RES);
31 double to_fraction =
Math::pi / (2 * (HALF_SIZE - 1));
32 for (
auto i :
xrange(HALF_SIZE)) {
33 double angle = ((i - HALF_SIZE) * 2 + 1) * to_angle;
34 out[i] = cstd::sin<2>(angle) / angle;
35 out[i] *= 0.54 - 0.46 * cstd::cos<2>((2 * i + 1) * to_fraction);
39 for (
auto i :
xrange(BLIP_RES)) {
40 end[i] = out[HALF_SIZE - 1 - i];
45 for (
auto i :
xrange(HALF_SIZE)) {
48 double rescale = 1.0 / (2.0 * total);
51 constexpr int IMPULSES_SIZE = BLIP_RES * (BLIP_IMPULSE_WIDTH / 2) + 1;
52 std::array<float, IMPULSES_SIZE> imp = {};
55 for (
auto i :
xrange(IMPULSES_SIZE)) {
56 imp[i] = float((next -
sum) * rescale);
58 next += fImpulse[i + BLIP_RES];
67 std::array<std::array<float, BLIP_IMPULSE_WIDTH>, BLIP_RES> result = {};
68 for (
auto phase :
xrange(BLIP_RES)) {
69 const auto* imp_fwd = &imp[BLIP_RES - phase];
70 const auto* imp_rev = &imp[phase];
71 auto* p = result[phase].data();
72 for (
size_t i :
xrange(BLIP_IMPULSE_WIDTH / 2)) {
73 *p++ = imp_fwd[BLIP_RES * i];
75 for (ptrdiff_t i = BLIP_IMPULSE_WIDTH / 2 - 1; i >= 0; --i) {
76 *p++ = imp_rev[BLIP_RES * i];
86 for (
auto i :
xrange(BLIP_RES)) {
87 std::cout <<
"\t{ " << impulses[i][0];
88 for (
auto j :
xrange(1, BLIP_IMPULSE_WIDTH)) {
89 std::cout <<
", " << impulses[i][j];
100 unsigned tmp = time.
toInt() + BLIP_IMPULSE_WIDTH;
101 assert(tmp < BUFFER_SIZE);
102 availSamp = std::max(availSamp, narrow<ptrdiff_t>(tmp));
105 auto ofst = time.
toInt() + offset;
106 const float* __restrict impulse = impulses[phase].data();
107 if ((ofst + BLIP_IMPULSE_WIDTH) <= BUFFER_SIZE) [[likely]] {
108 float* __restrict result = &buffer[ofst];
109 for (
auto i :
xrange(BLIP_IMPULSE_WIDTH)) {
110 result[i] += impulse[i] * delta;
113 for (
auto i :
xrange(BLIP_IMPULSE_WIDTH)) {
114 buffer[(ofst + i) & BUFFER_MASK] += impulse[i] * delta;
119static constexpr float BASS_FACTOR = 511.0f / 512.0f;
121template<
size_t PITCH>
122void BlipBuffer::readSamplesHelper(
float* __restrict out,
size_t samples)
124 assert((offset + samples) <= BUFFER_SIZE);
127 for (
auto i :
xrange(samples)) {
128 out[i * PITCH] = acc;
135 offset = ofst & BUFFER_MASK;
138static bool isSilent(
float x)
146 constexpr float threshold = 1.0f / 32768;
147 return std::abs(x) < threshold;
151template<
size_t PITCH>
154 if (availSamp <= 0) {
157 assert(
ranges::all_of(buffer, [](
const auto& b) {
return b == 0.0f; }));
159 if (isSilent(accum)) {
163 for (
auto i :
xrange(samples)) {
164 out[i * PITCH] = acc;
169 availSamp -= narrow<ptrdiff_t>(samples);
170 auto t1 = std::min(samples, BUFFER_SIZE - offset);
171 readSamplesHelper<PITCH>(out, t1);
174 auto t2 = samples - t1;
175 assert(t2 < BUFFER_SIZE);
176 readSamplesHelper<PITCH>(&out[t1 * PITCH], t2);
178 assert(offset < BUFFER_SIZE);
183template bool BlipBuffer::readSamples<1>(
float*,
size_t);
184template bool BlipBuffer::readSamples<2>(
float*,
size_t);
bool readSamples(float *out, size_t samples)
static constexpr int BLIP_PHASE_BITS
void addDelta(TimeIndex time, float delta)
A fixed point number, implemented by a 32-bit signed integer.
constexpr int toInt() const
Returns the integer part (rounded down) of this fixed point number.
constexpr unsigned fractAsInt() const
Returns the fractional part of this value as an integer.
This file implemented 3 utility functions:
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
uint32_t next(octet_iterator &it, octet_iterator end)
constexpr auto sum(InputRange &&range, Proj proj={})
constexpr auto xrange(T e)
constexpr auto end(const zstring_view &x)