Krotos Modules 3
Loading...
Searching...
No Matches
GrainDisplay.cpp
Go to the documentation of this file.
1#include "GrainDisplay.h"
2
3namespace krotos
4{
5 const String GrainDisplay::GRAIN_DISPLAY_UPDATE_ID{"GrainDisplay::update"};
6
8 {
9 for (int i = 0; i < MAX_DRAWN_GRAINS; i++)
10 {
11 m_grainIndices[i] = -1;
12 }
13 }
14
16
30
32 {
33 if (m_sampleEngine != nullptr)
34 {
36 }
37 return Range<float>(0.f, 1.f);
38 }
39
51
53 {
54 if (m_grainArray == nullptr)
55 {
56 // no grains to organise
57 return;
58 }
59
60 int grainIndex = 0;
61 for (int i = 0; i < MAX_DRAWN_GRAINS; i++)
62 {
63 if (m_grainIndices[i] == -1 || m_grainArray[m_grainIndices[i]].isPlaying == false)
64 {
65 // change grain
66 for (int j = grainIndex; j < SampleEngine::MAX_NUM_GRAINS; j++)
67 {
68 if (checkGrain(j) == true)
69 {
70 float trans = m_grainArray[j].grainWindow;
71
72 if (trans > 0.1f)
73 {
74 // only looking for new-ish grains
75 continue;
76 }
77
78 m_grainIndices[i] = j;
79 grainIndex = j + 1;
80 break;
81 }
82 }
83 }
84 }
85 }
86
88 {
89 if (m_grainArray != nullptr)
90 {
91 if (m_grainArray[index].isPlaying == true)
92 {
93 for (int i = 0; i < MAX_DRAWN_GRAINS; i++)
94 {
95 if (m_grainIndices[i] == index)
96 {
97 // already drawing this grain
98 return false;
99 }
100 }
101 return true;
102 }
103 }
104 return false;
105 }
106
107 void GrainDisplay::paint(juce::Graphics& g)
108 {
109 static const int NUM_WAVELET_SAMPLES{100};
110
111 // sanity check
112 if (m_sampleEngine == nullptr)
113 {
114 return;
115 }
116
117 if (this->isEnabled() == false || !m_sampleEngine->getNumAudioSegments())
118 {
119 // if not enabled don't draw
120 return;
121 }
122
123 String sDisplay;
124
125 if (m_grainArray != nullptr)
126 {
127 bool showEggs{false};
128 bool showPlayheads{true};
129
131 {
133 showEggs = false;
134 showPlayheads = true;
135 break;
137 showEggs = false;
138 showPlayheads = true;
139 break;
141 showEggs = true;
142 showPlayheads = false;
143 break;
144 }
145
146 bool isFirstPlayingGrain = true;
147 float waveletSamples[NUM_WAVELET_SAMPLES];
148 bool waveletSamplesValid = false;
149
150 for (int i = 0; i < MAX_DRAWN_GRAINS; i++)
151 {
152 if (m_grainArray[m_grainIndices[i]].isPlaying == true)
153 {
154 if (m_grainIndices[i] >= 0)
155 {
156 float grainHeight = jlimit<float>(0.f, 1.f, m_grainArray[m_grainIndices[i]].envelope);
157 float halfGrainHeight = grainHeight * 0.5f;
158
159 if (showEggs)
160 {
161 // Draw filled ellipse around entire grain region
162 float positionStartPercent =
164 float widthPercent = m_grainArray[m_grainIndices[i]].length / (float)m_numSamples;
166 {
167 g.setColour(Colours::green.withAlpha(1.0f));
168 }
170 {
171 g.setColour(Colours::red.withAlpha(1.0f));
172 }
174 {
175 g.setColour(Colours::violet.withAlpha(0.2f));
176 }
177 else
178 {
179 g.setColour(Colours::orange.withAlpha(0.2f));
180 }
182 g, {positionStartPercent,
183 0.5f - m_grainArray[m_grainIndices[i]].mix * grainHeight * 0.5f, widthPercent,
184 m_grainArray[m_grainIndices[i]].mix * grainHeight});
185 }
186 const bool hasSampleAccess = m_sampleOscillatorSound != nullptr &&
188 if (showPlayheads && hasSampleAccess)
189 {
190 // Draw in the playheads for each of the channels in the sample
191 float position = m_grainArray[m_grainIndices[i]].playHeadStart +
194 float percentage = (position / (float)m_numSamples);
195 float centerHeight = 0.5f;
196
197 if (position >= 0)
198 {
199 g.setColour(m_playheadColour);
200
202 {
204 {
205 g.setColour(Colours::yellow.withAlpha(
206 jmin<float>(0.25f + halfGrainHeight * 2.0f, 1.f)));
207 }
208 else
209 {
210 g.setColour(Colours::lightgoldenrodyellow.withAlpha(
211 jmin<float>(0.25f + halfGrainHeight * 2.0f, 1.f)));
212 }
214 {percentage, centerHeight + halfGrainHeight, percentage,
215 centerHeight - halfGrainHeight},
216 2);
217
218 int voiceIndex = m_grainArray[m_grainIndices[i]].voiceIndex;
219 if (voiceIndex >= 0)
220 {
221 Rectangle<float> voiceIndexBounds;
222 voiceIndexBounds.setPosition(percentage + 0.005f, centerHeight);
223 voiceIndexBounds.setSize(0.2f, 0.3f);
224 drawNormalisedZoomedText(g, String(voiceIndex + 1), voiceIndexBounds);
225 }
226
227 // Draw indicator for audio ADSR output value
228 float yPosition = 1.f - m_grainArray[m_grainIndices[i]].gainMod;
229 g.setColour(Colours::cyan);
231 g, {percentage - 0.01f, yPosition, percentage + 0.01f, yPosition}, 2);
232
233 // Draw indicator for pitch ADSR output value
234 yPosition = 1.f - m_grainArray[m_grainIndices[i]].pitchMod;
235 g.setColour(Colours::magenta);
237 g, {percentage - 0.01f, yPosition, percentage + 0.01f, yPosition}, 2);
238 }
239 else
240 {
243 {
244 drawNormalisedZoomedLine(g, {percentage, 0.0f, percentage, 1.0f}, 2);
245 }
246 else
247 {
249 {percentage, centerHeight + halfGrainHeight,
250 percentage, centerHeight - halfGrainHeight},
251 2);
252 }
253 }
254 }
255 // finish accessing the sample
257 }
258
259 if (isFirstPlayingGrain)
260 {
261 isFirstPlayingGrain = false;
262
263 float startIndex = static_cast<float>(m_grainArray[m_grainIndices[i]].playHeadStart);
264 float increment = static_cast<float>(m_grainArray[m_grainIndices[i]].grainSize /
265 static_cast<float>(NUM_WAVELET_SAMPLES));
266
267 float min = 1000.f, max = -1000.f;
268 for (int wSample = 0; wSample < NUM_WAVELET_SAMPLES; wSample++)
269 {
270 waveletSamples[wSample] = m_sampleEngine->getSample(0, startIndex);
271
272 if (waveletSamples[wSample] < min)
273 min = waveletSamples[wSample];
274 if (waveletSamples[wSample] > max)
275 max = waveletSamples[wSample];
276
277 startIndex += increment;
278 if (static_cast<int>(startIndex) > m_sampleEngine->getNumSamples() - 1)
279 break;
280 }
281
282 if (max > min) // Sanity check
283 {
284 for (int wSample = 0; wSample < NUM_WAVELET_SAMPLES; wSample++)
285 {
286 waveletSamples[wSample] = jmap<float>(waveletSamples[wSample], min, max, 0.f, 1.f);
287 }
288 waveletSamplesValid = true;
289 }
290 }
291 }
292 }
293 } // Every grain
294
295 // Draw in sample engine data if there is any (red line)
297 {
299 {
300 std::vector<AudioDescriptor>& grainDescriptionByTime = m_sampleEngine->getGrainDescriptionByTime();
301
302 float minY = 10000000.0f;
303 float maxY = 0.0f;
304
305 // Draw in phase0 (grain) boundaries
306 float numSamples = float(m_sampleEngine->getNumSamples());
307 g.setColour(Colours::cyan.withAlpha(0.3f));
308 for (auto& grainDescription : grainDescriptionByTime)
309 {
310 float xPosition = float(grainDescription.audioIndex) / numSamples;
311 drawNormalisedZoomedLine(g, {xPosition, 0.f, xPosition, 1.f}, 1);
312 if (grainDescription.frequency > maxY)
313 maxY = grainDescription.frequency;
314 if (grainDescription.frequency < minY)
315 minY = grainDescription.frequency;
316 }
317
318 // Draw in phase boundary markers (Red line)
319 bool first{true};
320 Path linePath;
321 for (auto& grainDescription : grainDescriptionByTime)
322 {
323 float xPosition = float(grainDescription.audioIndex) / numSamples;
324 float yPosition = jmap<float>(grainDescription.frequency, minY, maxY, 1.0f, 0.0f);
325 if (first)
326 {
327 linePath.startNewSubPath(xPosition, yPosition);
328 }
329 else
330 {
331 linePath.lineTo(xPosition, yPosition);
332 }
333 first = false;
334 }
335 g.setColour(Colours::red.withAlpha(0.9f));
336 drawNormalisedZoomedPath(g, linePath, 3.0f);
337
338 // Draw in a couple of general purpose indicators
339 // Once the use of these is settled, they may be renamed accordingly
340
341 // Set up a line for Indicator 1
342 float indicator1Value = 1.f - m_sampleEngine->getIndicator1();
343 Line<float> line1 = Line<float>(0.f, indicator1Value * static_cast<float>(getHeight()),
344 static_cast<float>(getWidth()) * 0.025f,
345 indicator1Value * static_cast<float>(getHeight()));
346 // Set up a line for Indicator 2
347 float indicator2Value = 1.f - m_sampleEngine->getIndicator2();
348 Line<float> line2 = Line<float>(0.f, indicator2Value * static_cast<float>(getHeight()), getWidth(),
349 indicator2Value * static_cast<float>(getHeight()));
350 // Draw shadows for the indicators
351 g.setColour(Colours::black.withAlpha(0.5f));
352 g.drawLine(line1, 5);
353 g.drawLine(line2, 2);
354 // Draw Indicator 1
355 g.setColour(Colours::yellow.withAlpha(1.f));
356 g.drawLine(line1, 3);
357 // Draw Indicator 2
358 g.setColour(Colours::lightcyan.withAlpha(1.f));
359 g.drawLine(line2, 1);
360
361 // Draw RPM display
362 sDisplay = "RPM: " + String(m_sampleEngine->getIndicatorRPM());
363 g.setColour(Colours::red.withAlpha(1.f));
364 g.drawFittedText(sDisplay, getWidth() / 2, 0, getWidth() / 4, getHeight() / 2,
365 Justification::centredLeft, 1);
366
367 // Draw in wavelet display
368 if (waveletSamplesValid)
369 {
370 Path waveletPath;
371 float wxPosition = 0.75f;
372 float xIncrement = 0.125f / static_cast<float>(NUM_WAVELET_SAMPLES);
373 waveletPath.startNewSubPath(wxPosition, waveletSamples[0]);
374 for (int wSample = 1; wSample < NUM_WAVELET_SAMPLES; wSample++)
375 {
376 wxPosition += xIncrement;
377 waveletPath.lineTo(wxPosition, waveletSamples[wSample]);
378 }
379 g.setColour(Colours::white.withAlpha(1.0f));
380 drawNormalisedZoomedPath(g, waveletPath, 1.0f);
381 }
382 }
383 }
384 }
385 }
386
388 {
389 if (m_grainArray == nullptr || m_sampleEngine == nullptr || m_sampleEngine->isPlaying() == false)
390 {
391 return 0.5f;
392 }
393 float playheadPos = m_grainArray[m_grainIndices[0]].playHeadStart +
395 playheadPos /= m_numSamples;
396 return playheadPos;
397 }
398} // namespace krotos
WaveformMode
Definition AreaSelectionComp.h:7
void organiseGrains()
Definition GrainDisplay.cpp:52
void paint(Graphics &g) override
Definition GrainDisplay.cpp:107
const Colour m_playheadColour
Definition GrainDisplay.h:61
SampleEngine * m_sampleEngine
Definition GrainDisplay.h:47
int m_numSamples
Definition GrainDisplay.h:53
int m_grainIndices[MAX_DRAWN_GRAINS]
Definition GrainDisplay.h:57
Range< float > getPlayingWaveformZoomRange()
Definition GrainDisplay.cpp:31
float getPlayheadPosition()
Definition GrainDisplay.cpp:387
void update()
Definition GrainDisplay.cpp:17
GrainDisplay()
Definition GrainDisplay.cpp:7
static const String GRAIN_DISPLAY_UPDATE_ID
Definition GrainDisplay.h:64
bool checkGrain(int index)
Definition GrainDisplay.cpp:87
KrotosSampleOscillatorSound * m_sampleOscillatorSound
Definition GrainDisplay.h:46
static const int MAX_DRAWN_GRAINS
Definition GrainDisplay.h:56
Grain * m_grainArray
Definition GrainDisplay.h:52
~GrainDisplay() override
Definition GrainDisplay.cpp:15
bool m_drawDebugGraphics
Definition GrainDisplay.h:60
AreaSelectionComp::WaveformMode getWaveformMode()
Definition GrainDisplay.cpp:40
int length
Definition OscillatorUtils.h:61
float gainMod
Definition OscillatorUtils.h:76
float pitchMod
Definition OscillatorUtils.h:77
float grainSize
Definition OscillatorUtils.h:60
int voiceIndex
Definition OscillatorUtils.h:75
@ vehicleStatic
Definition OscillatorUtils.h:51
@ vehicleMoving
Definition OscillatorUtils.h:50
@ background
Definition OscillatorUtils.h:53
int playHeadStart
Definition OscillatorUtils.h:58
float mix
Definition OscillatorUtils.h:57
float grainWindow
Definition OscillatorUtils.h:62
bool analysisResultsAreValid()
Definition KrotosAudioBufferDSP.h:422
std::vector< AudioDescriptor > & getGrainDescriptionByTime()
Definition KrotosAudioBufferDSP.h:452
bool requestAccess(const StringRef id)
Called by a client to request access to the resource.
Definition ResourceLock.cpp:5
void finishedAccessing(const StringRef id)
Called by a client to inform the resource that it no longer needs access.
Definition ResourceLock.cpp:35
float getIndicator2()
Definition SampleEngine.cpp:87
float getIndicatorRPM()
Definition SampleEngine.cpp:90
static const int MAX_NUM_GRAINS
Definition SampleEngine.h:88
float getIndicator1()
Definition SampleEngine.cpp:84
int getNumAudioSegments()
Definition SampleEngine.h:161
GranularPlaybackMode getGranularOscillatorTypeIndicator()
Definition SampleEngine.h:135
bool isPlaying()
returns true if any grains are active
Definition SampleEngine.cpp:17
Range< float > getPlayingWaveformZoomRange()
Definition SampleEngine.h:174
void drawNormalisedZoomedPath(Graphics &g, const Path &path, float thickness)
Definition ZoomableComponent.cpp:57
void drawNormalisedZoomedText(Graphics &g, String text, Rectangle< float > bounds) const
Definition ZoomableComponent.cpp:41
void drawNormalisedZoomedLine(Graphics &g, Line< float > line, float thickness) const
Definition ZoomableComponent.cpp:35
void drawNormalisedZoomedEllipse(Graphics &g, const Rectangle< float > &bounds)
Definition ZoomableComponent.cpp:85
Definition AirAbsorptionFilter.cpp:2