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.

247 lines
7.0KB

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