Deluge Firmware
Loading...
Searching...
No Matches
renderWave.h
Go to the documentation of this file.
1/*
2 * Copyright © 2017-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17
19
20
21#define setupAmplitudeVector(i) { \
22 amplitude += amplitudeIncrement; \
23 amplitudeVector = vsetq_lane_s32(amplitude >> 1, amplitudeVector, i); \
24}
25
26
27#define RENDER_OSC_SYNC(storageFunctionName, valueFunctionName, extraInstructionsForCrossoverSampleRedo, startRenderingASyncLabel) \
28 \
29 bool renderedASyncFromItsStartYet = false; \
30 int32_t crossoverSampleBeforeSync; \
31 int32_t fadeBetweenSyncs; \
32 \
33 \
34 /* Do a bunch of samples until we get to the next crossover sample */ \
35 uint32_t samplesIncludingNextCrossoverSample = 1; /* A starting value that'll be added to. It's 1 because we want to include the 1 extra sample at the end - the crossover sample. */ \
36startRenderingASyncLabel: \
37 uint32_t distanceTilNextCrossoverSample = -resetterPhase - (resetterPhaseIncrement >> 1); \
38 samplesIncludingNextCrossoverSample += (uint32_t)(distanceTilNextCrossoverSample - 1) / resetterPhaseIncrement; \
39 bool shouldBeginNextSyncAfter = (numSamplesThisOscSyncSession >= samplesIncludingNextCrossoverSample); \
40 int numSamplesThisSyncRender = shouldBeginNextSyncAfter ? samplesIncludingNextCrossoverSample : numSamplesThisOscSyncSession; /* Just limit it, basically. */ \
41 \
42 int32_t const* const bufferEndThisSyncRender = bufferStartThisSync + numSamplesThisSyncRender; \
43 uint32_t phaseTemp = phase; \
44 int32_t* __restrict__ writePos = bufferStartThisSync; \
45 \
46 storageFunctionName(valueFunctionName); \
47 \
48 /* Sort out the crossover sample at the *start* of that window we just did, if there was one. */ \
49 if (renderedASyncFromItsStartYet) { \
50 int32_t average = (*bufferStartThisSync >> 1) + (crossoverSampleBeforeSync >> 1); \
51 int32_t halfDifference = (*bufferStartThisSync >> 1) - (crossoverSampleBeforeSync >> 1); \
52 int32_t sineValue = getSine(fadeBetweenSyncs >> 1); \
53 *bufferStartThisSync = average + (multiply_32x32_rshift32(halfDifference, sineValue) << 1); \
54 } \
55 \
56 if (shouldBeginNextSyncAfter) { \
57 /* We've just done a crossover (i.e. hit a sync point) at the end of that window, so start thinking about that and planning the next window. */ \
58 bufferStartThisSync += samplesIncludingNextCrossoverSample - 1; \
59 crossoverSampleBeforeSync = *bufferStartThisSync; \
60 numSamplesThisOscSyncSession -= samplesIncludingNextCrossoverSample - 1; \
61 extraInstructionsForCrossoverSampleRedo; \
62 \
63 resetterPhase += resetterPhaseIncrement * (samplesIncludingNextCrossoverSample - renderedASyncFromItsStartYet); /* We want this to always show one sample late at this point (why again?). */ \
64 /* The first time we get here, it won't yet be, so make it so. */ \
65 \
66 fadeBetweenSyncs = multiply_32x32_rshift32((int32_t)resetterPhase, resetterDivideByPhaseIncrement) /* The result of that comes out as between "-0.5 and 0.5", represented as +-(1<<14) */ \
67 << 17; /* And this makes it "full-scale", so "1" is 1<<32. */ \
68 phase = multiply_32x32_rshift32(fadeBetweenSyncs, phaseIncrement) + retriggerPhase; \
69 \
70 phase -= phaseIncrement; /* Because we're going back and redoing the last sample. */ \
71 renderedASyncFromItsStartYet = true; \
72 samplesIncludingNextCrossoverSample = 2; /* Make this 1 higher now, because resetterPhase's value is 1 sample later than what it "is in reality". */ \
73 goto startRenderingASyncLabel; \
74 } \
75 \
76 /* We're not beginning a next sync, so are not going to reset phase, so need to update (increment) it to keep it valid. */ \
77 phase += phaseIncrement * numSamplesThisSyncRender;
78
79
80
81#define RENDER_WAVETABLE_LOOP(dontCare) { \
82 doRenderingLoop (bufferStartThisSync, bufferEndThisSyncRender, firstCycleNumber, bandHere, phaseTemp, phaseIncrement, crossCycleStrength2, crossCycleStrength2Increment, kernel); \
83}
84
85#define RENDER_SINGLE_CYCLE_WAVEFORM_LOOP(dontCare) { \
86 doRenderingLoopSingleCycle (bufferStartThisSync, bufferEndThisSyncRender, bandHere, phaseTemp, phaseIncrement, kernel); \
87}
88
89#define WAVETABLE_EXTRA_INSTRUCTIONS_FOR_CROSSOVER_SAMPLE_REDO { \
90 crossCycleStrength2 += crossCycleStrength2Increment * (samplesIncludingNextCrossoverSample - 1); \
91}
92
93
94#define STORE_VECTOR_WAVE_FOR_ONE_SYNC(vectorValueFunctionName) { \
95 do { \
96 int32x4_t valueVector; \
97 vectorValueFunctionName(); \
98 vst1q_s32(writePos, valueVector); \
99 writePos += 4; \
100 } while (writePos < bufferEndThisSyncRender); \
101}
102
103#define SETUP_FOR_APPLYING_AMPLITUDE_WITH_VECTORS() \
104 int32x4_t amplitudeVector; \
105 setupAmplitudeVector(0) \
106 setupAmplitudeVector(1) \
107 setupAmplitudeVector(2) \
108 setupAmplitudeVector(3) \
109 int32x4_t amplitudeIncrementVector = vdupq_n_s32(amplitudeIncrement << 1);
110
111
112/* Before calling, you must:
113 amplitude <<= 1;
114 amplitudeIncrement <<= 1;
115*/
116#define CREATE_WAVE_RENDER_FUNCTION_INSTANCE(thisFunctionInstanceName, vectorValueFunctionName) \
117\
118__attribute__((optimize("unroll-loops"))) \
119void thisFunctionInstanceName(const int16_t* __restrict__ table, int tableSizeMagnitude, int32_t amplitude, int32_t* __restrict__ outputBuffer, int32_t* bufferEnd, \
120 uint32_t phaseIncrement, uint32_t phase, bool applyAmplitude, uint32_t phaseToAdd, int32_t amplitudeIncrement) { \
121 \
122 int16x4_t const32767 = vdup_n_s16(32767); \
123 int32_t* __restrict__ outputBufferPos = outputBuffer; \
124 SETUP_FOR_APPLYING_AMPLITUDE_WITH_VECTORS(); \
125 uint32_t phaseTemp = phase; \
126 \
127 do { \
128 int32x4_t valueVector; \
129 \
130 vectorValueFunctionName(); \
131 \
132 if (applyAmplitude) { \
133 int32x4_t existingDataInBuffer = vld1q_s32(outputBufferPos); \
134 valueVector = vqdmulhq_s32(amplitudeVector, valueVector); \
135 amplitudeVector = vaddq_s32(amplitudeVector, amplitudeIncrementVector); \
136 valueVector = vaddq_s32(valueVector, existingDataInBuffer); \
137 } \
138 \
139 vst1q_s32(outputBufferPos, valueVector); \
140 \
141 outputBufferPos += 4; \
142 } \
143 while (outputBufferPos < bufferEnd); \
144};