The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
6.9KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated!
  4. ==============================================================================
  5. */
  6. #include "../JuceLibraryCode/JuceHeader.h"
  7. //==============================================================================
  8. class MainContentComponent : public AudioAppComponent,
  9. private Timer
  10. {
  11. public:
  12. //==============================================================================
  13. MainContentComponent()
  14. : pos (299, 299),
  15. waveTableIndex (0),
  16. bufferIndex (0),
  17. sampleRate (0.0),
  18. expectedSamplesPerBlock (0),
  19. dragging (false)
  20. {
  21. setSize (600, 600);
  22. for (int i = 0; i < numElementsInArray (waveValues); ++i)
  23. zeromem (waveValues[i], sizeof (waveValues[i]));
  24. // specify the number of input and output channels that we want to open
  25. setAudioChannels (2, 2);
  26. startTimerHz (60);
  27. }
  28. ~MainContentComponent()
  29. {
  30. shutdownAudio();
  31. }
  32. //==============================================================================
  33. void prepareToPlay (int samplesPerBlockExpected, double newSampleRate) override
  34. {
  35. sampleRate = newSampleRate;
  36. expectedSamplesPerBlock = samplesPerBlockExpected;
  37. }
  38. /* This method generates the actual audio samples.
  39. In this example the buffer is filled with a sine wave whose frequency and
  40. amplitude are controlled by the mouse position.
  41. */
  42. void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
  43. {
  44. bufferToFill.clearActiveBufferRegion();
  45. for (int chan = 0; chan < bufferToFill.buffer->getNumChannels(); ++chan)
  46. {
  47. int ind = waveTableIndex;
  48. float* const channelData = bufferToFill.buffer->getWritePointer (chan, bufferToFill.startSample);
  49. for (int i = 0; i < bufferToFill.numSamples; ++i)
  50. {
  51. if (isPositiveAndBelow (chan, numElementsInArray (waveValues)))
  52. {
  53. channelData[i] = waveValues[chan][ind % wavetableSize];
  54. ++ind;
  55. }
  56. }
  57. }
  58. waveTableIndex = (int) (waveTableIndex + bufferToFill.numSamples) % wavetableSize;
  59. }
  60. void releaseResources() override
  61. {
  62. // This gets automatically called when audio device parameters change
  63. // or device is restarted.
  64. stopTimer();
  65. }
  66. //==============================================================================
  67. void paint (Graphics& g) override
  68. {
  69. // (Our component is opaque, so we must completely fill the background with a solid colour)
  70. g.fillAll (Colours::black);
  71. Point<float> nextPos = pos + delta;
  72. if (nextPos.x < 10 || nextPos.x + 10 > getWidth())
  73. {
  74. delta.x = -delta.x;
  75. nextPos.x = pos.x + delta.x;
  76. }
  77. if (nextPos.y < 50 || nextPos.y + 10 > getHeight())
  78. {
  79. delta.y = -delta.y;
  80. nextPos.y = pos.y + delta.y;
  81. }
  82. if (! dragging)
  83. {
  84. writeInterpolatedValue (pos, nextPos);
  85. pos = nextPos;
  86. }
  87. else
  88. {
  89. pos = lastMousePosition;
  90. }
  91. // draw a circle
  92. g.setColour (Colours::grey);
  93. g.fillEllipse (pos.x, pos.y, 20, 20);
  94. drawWaveform (g, 20.0f, 0);
  95. drawWaveform (g, 40.0f, 1);
  96. }
  97. void drawWaveform (Graphics& g, float y, int channel) const
  98. {
  99. const int pathWidth = 2000;
  100. Path wavePath;
  101. wavePath.startNewSubPath (0.0f, y);
  102. for (int i = 1; i < pathWidth; ++i)
  103. wavePath.lineTo ((float) i, (1.0f + waveValues[channel][i * numElementsInArray (waveValues[0]) / pathWidth]) * 10.0f);
  104. g.strokePath (wavePath, PathStrokeType (1.0f),
  105. wavePath.getTransformToScaleToFit (Rectangle<float> (0.0f, y, (float) getWidth(), 20.0f), false));
  106. }
  107. // Mouse handling..
  108. void mouseDown (const MouseEvent& e) override
  109. {
  110. lastMousePosition = e.position;
  111. mouseDrag (e);
  112. dragging = true;
  113. }
  114. void mouseDrag (const MouseEvent& e) override
  115. {
  116. dragging = true;
  117. if (e.position != lastMousePosition)
  118. {
  119. // calculate movement vector
  120. delta = e.position - lastMousePosition;
  121. waveValues[0][bufferIndex % wavetableSize] = xToAmplitude (e.position.x);
  122. waveValues[1][bufferIndex % wavetableSize] = yToAmplitude (e.position.y);
  123. ++bufferIndex;
  124. lastMousePosition = e.position;
  125. }
  126. }
  127. void mouseUp (const MouseEvent&) override
  128. {
  129. dragging = false;
  130. }
  131. void writeInterpolatedValue (Point<float> lastPosition,
  132. Point<float> currentPosition)
  133. {
  134. Point<float> start, finish;
  135. if (lastPosition.getX() > currentPosition.getX())
  136. {
  137. finish = lastPosition;
  138. start = currentPosition;
  139. }
  140. else
  141. {
  142. start = lastPosition;
  143. finish = currentPosition;
  144. }
  145. for (int i = 0; i < steps; ++i)
  146. {
  147. Point<float> p = start + ((finish - start) * i) / steps;
  148. const int index = (bufferIndex + i) % wavetableSize;
  149. waveValues[1][index] = yToAmplitude (p.y);
  150. waveValues[0][index] = xToAmplitude (p.x);
  151. }
  152. bufferIndex = (bufferIndex + steps) % wavetableSize;
  153. }
  154. float indexToX (int indexValue) const noexcept
  155. {
  156. return (float) indexValue;
  157. }
  158. float amplitudeToY (float amp) const noexcept
  159. {
  160. return getHeight() - (amp + 1.0f) * getHeight() / 2.0f;
  161. }
  162. float xToAmplitude (float x) const noexcept
  163. {
  164. return jlimit (-1.0f, 1.0f, 2.0f * (getWidth() - x) / getWidth() - 1.0f);
  165. }
  166. float yToAmplitude (float y) const noexcept
  167. {
  168. return jlimit (-1.0f, 1.0f, 2.0f * (getHeight() - y) / getHeight() - 1.0f);
  169. }
  170. void timerCallback() override
  171. {
  172. repaint();
  173. }
  174. private:
  175. //==============================================================================
  176. enum
  177. {
  178. wavetableSize = 36000,
  179. steps = 10
  180. };
  181. Point<float> pos, delta;
  182. int waveTableIndex;
  183. int bufferIndex;
  184. double sampleRate;
  185. int expectedSamplesPerBlock;
  186. Point<float> lastMousePosition;
  187. float waveValues[2][wavetableSize];
  188. bool dragging;
  189. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
  190. };
  191. // (This is called from Main.cpp)
  192. Component* createMainContentComponent() { return new MainContentComponent(); };