f@0
|
1 #pragma once
|
f@0
|
2
|
f@0
|
3
|
f@0
|
4 #include "cinder/app/App.h"
|
f@0
|
5 #include "cinder/gl/gl.h"
|
f@0
|
6 #include "cinder/gl/Batch.h"
|
f@0
|
7
|
f@0
|
8
|
f@0
|
9 #include "Chunk.h"
|
f@0
|
10 #include "DrawInfo.h"
|
f@0
|
11
|
f@0
|
12 #ifdef USE_PARTICLES
|
f@0
|
13 #include "ParticleController.h"
|
f@0
|
14 #endif
|
f@0
|
15
|
f@0
|
16 #include "cinder/Color.h"
|
f@0
|
17 #include "cinder/PolyLine.h"
|
f@0
|
18 #include "cinder/Rand.h"
|
f@0
|
19
|
f@0
|
20 #include <vector>
|
f@0
|
21 #include <map>
|
f@0
|
22
|
f@0
|
23
|
f@0
|
24 class DrawInfo;
|
f@0
|
25 typedef int SynthID;
|
f@0
|
26
|
f@0
|
27
|
f@0
|
28 using ci::ivec2;
|
f@0
|
29 using ci::vec2;
|
f@0
|
30 using ci::Color;
|
f@0
|
31 using ci::ColorA;
|
f@0
|
32
|
f@3
|
33 /**
|
f@3
|
34 * A Cursor is the white thingy that loops through the selection when Collidoscope is played.
|
f@3
|
35 */
|
f@0
|
36 struct Cursor {
|
f@0
|
37 static const int kNoPosition = -100;
|
f@0
|
38 int pos;
|
f@0
|
39 double lastUpdate;
|
f@0
|
40 };
|
f@0
|
41
|
f@3
|
42 /**
|
f@3
|
43 * Collidoscope's graphical wave
|
f@3
|
44 *
|
f@3
|
45 */
|
f@0
|
46 class Wave
|
f@0
|
47 {
|
f@0
|
48 friend class ParticleController;
|
f@0
|
49
|
f@0
|
50 public:
|
f@0
|
51
|
f@3
|
52 /**
|
f@3
|
53 * The selection of the wave that is controlled by the big horizontal knob
|
f@3
|
54 *
|
f@3
|
55 */
|
f@0
|
56 class Selection {
|
f@0
|
57
|
f@0
|
58 public:
|
f@0
|
59
|
f@0
|
60 Selection( Wave * w, Color color );
|
f@0
|
61
|
f@3
|
62 /** Sets the start of selection. start is the index of the first chunk of the selection */
|
f@0
|
63 void setStart( size_t start );
|
f@0
|
64
|
f@3
|
65 /** Sets the size of selection. size is the number of chunks the selection is made of */
|
f@0
|
66 void setSize( size_t size );
|
f@0
|
67
|
f@3
|
68 /** Particle spread is used to calculate the size of the cloud of particles */
|
f@0
|
69 void inline setParticleSpread( float spread ){
|
f@0
|
70 mParticleSpread = spread;
|
f@0
|
71 }
|
f@0
|
72
|
f@0
|
73 size_t getStart(void) const { return mSelectionStart; }
|
f@0
|
74
|
f@0
|
75 size_t getEnd(void) const { return mSelectionEnd; }
|
f@0
|
76
|
f@0
|
77 size_t inline getSize(void) const {
|
f@0
|
78 if (mNull)
|
f@0
|
79 return 0;
|
f@0
|
80 else
|
f@0
|
81 return 1 + mSelectionEnd - mSelectionStart;
|
f@0
|
82 }
|
f@0
|
83
|
f@0
|
84 float inline getParticleSpread() const { return mParticleSpread; }
|
f@0
|
85
|
f@3
|
86 /** When selection is null no selection is showed on the wave */
|
f@0
|
87 inline void setToNull(){
|
f@0
|
88 mParticleSpread = 1.0f;
|
f@0
|
89 mNull = true;
|
f@0
|
90 }
|
f@0
|
91
|
f@0
|
92 inline bool isNull() const{
|
f@0
|
93 return mNull;
|
f@0
|
94 }
|
f@0
|
95
|
f@0
|
96 inline const Color & getColor() const{
|
f@0
|
97 return mColor;
|
f@0
|
98 }
|
f@0
|
99
|
f@0
|
100 private:
|
f@0
|
101
|
f@0
|
102 size_t mSelectionStart;
|
f@0
|
103
|
f@0
|
104 size_t mSelectionEnd;
|
f@0
|
105
|
f@0
|
106 float mParticleSpread;
|
f@0
|
107
|
f@0
|
108 bool mNull = true;
|
f@0
|
109
|
f@0
|
110 Color mColor;
|
f@0
|
111
|
f@0
|
112 Wave * mWave;
|
f@0
|
113
|
f@0
|
114 }; // class Selection
|
f@0
|
115
|
f@0
|
116
|
f@0
|
117
|
f@0
|
118 #ifdef USE_PARTICLES
|
f@0
|
119 ParticleController mParticleController;
|
f@0
|
120 #endif
|
f@0
|
121
|
f@0
|
122
|
f@0
|
123
|
f@3
|
124 /* Maps id of the synth to cursor. There is one cursor for each Synth being played */
|
f@0
|
125 std::map < SynthID, Cursor > mCursors;
|
f@3
|
126 /** Holds the positions of the cursor, namely on which chunk the cursor is currently */
|
f@0
|
127 std::vector<int> mCursorsPos;
|
f@0
|
128
|
f@0
|
129 public:
|
f@0
|
130
|
f@3
|
131 // value used to identify the loop for cursor position
|
f@0
|
132 static const int kLoopNote = -1;
|
f@0
|
133 static const cinder::Color CURSOR_CLR;
|
f@0
|
134 /* must be in sync with supercollider durationFactor ControlSpec max */
|
f@0
|
135 static const int MAX_DURATION = 8;
|
f@0
|
136 #ifdef USE_PARTICLES
|
f@0
|
137 static const int PARTICLESIZE_COEFF = 40;
|
f@0
|
138 #endif
|
f@0
|
139
|
f@3
|
140 /** Resetting a wave makes it shrink until it disappears. Each time a new sample is recorder the wave is reset
|
f@3
|
141 * \param onlyChunks if false the selection is also set to null, if true only the chunks are reset
|
f@3
|
142 */
|
f@0
|
143 void reset(bool onlyChunks);
|
f@0
|
144
|
f@3
|
145 /** sets top and bottom values for the chunk.
|
f@3
|
146 * \a bottom and \a top are in audio coordinates [-1.0, 1.0]
|
f@3
|
147 */
|
f@0
|
148 void setChunk(size_t index, float bottom, float top);
|
f@0
|
149
|
f@0
|
150 const Chunk & getChunk(size_t index);
|
f@0
|
151
|
f@3
|
152 /** places the cursor on the wave. Every cursor is associated to a synth voice of the audio engine.
|
f@3
|
153 * The synth id identifies uniquely the cursor in the internal map of the wave.
|
f@3
|
154 * If the cursor doesn't exist it is created */
|
f@0
|
155 inline void setCursorPos( SynthID id, int pos, const DrawInfo& di ){
|
f@0
|
156
|
f@0
|
157 Cursor & cursor = mCursors[id];
|
f@0
|
158 cursor.pos = pos;
|
f@0
|
159 cursor.lastUpdate = ci::app::getElapsedSeconds();
|
f@0
|
160
|
f@0
|
161 #ifdef USE_PARTICLES
|
f@3
|
162 // The idea is that, if the duration is greater than 1.0, the cursor continues in form of particles
|
f@3
|
163 // The smaller the selection the more particles; the bigger the duration the more particles
|
f@0
|
164 if (mSelection.getParticleSpread() > 1.0f){
|
f@0
|
165 /* amountCoeff ranges from 1/8 to 1 */
|
f@0
|
166 const float amountCoeff = (mSelection.getParticleSpread() / MAX_DURATION);
|
f@0
|
167
|
f@0
|
168 /* get radom point within seleciton as center of the particle */
|
f@0
|
169 vec2 centrePoint; // was former getRandomPoint
|
f@0
|
170 const int randomChunkIndex = ci::Rand::randInt(mSelection.getStart(), mSelection.getEnd() );
|
f@0
|
171
|
f@0
|
172 centrePoint.x = di.flipX( 1 + (randomChunkIndex * (2 + Chunk::kWidth)) + Chunk::kWidth / 2 );
|
f@0
|
173 centrePoint.y = di.flipY( di.audioToHeigt(0.0) );
|
f@0
|
174
|
f@0
|
175 const float wavePixelLen = mNumChunks * ( 2 + Chunk::kWidth);
|
f@0
|
176 centrePoint.x *= float(di.getWindowWidth()) / wavePixelLen;
|
f@0
|
177
|
f@0
|
178 mParticleController.addParticles(
|
f@0
|
179 std::max( 1, (int)(amountCoeff * ParticleController::kMaxParticleAdd * mFilterCoeff) ), // amount of particles to add
|
f@0
|
180 centrePoint,
|
f@0
|
181 mSelection.getParticleSpread() * PARTICLESIZE_COEFF // size of the cloud
|
f@0
|
182 );
|
f@0
|
183 }
|
f@0
|
184 #endif
|
f@0
|
185
|
f@0
|
186
|
f@0
|
187 }
|
f@0
|
188
|
f@0
|
189 void update( double secondsPerChunk, const DrawInfo& di );
|
f@0
|
190
|
f@0
|
191 void removeCursor( SynthID id ) { mCursors.erase( id ); }
|
f@0
|
192
|
f@3
|
193 /** Sets the transparency of this wave. \a alpha ranges from 0 to 1 */
|
f@0
|
194 inline void setselectionAlpha(float alpha){ mFilterCoeff = alpha;}
|
f@0
|
195
|
f@0
|
196 void draw( const DrawInfo& di );
|
f@0
|
197
|
f@0
|
198 Selection& getSelection() { return mSelection; };
|
f@0
|
199
|
f@0
|
200 size_t getSize() const{ return mChunks.size(); }
|
f@0
|
201
|
f@0
|
202 void setScopePoint(int index, float audioVal);
|
f@0
|
203
|
f@0
|
204 Wave( size_t numChunks, Color selectionColor );
|
f@0
|
205
|
f@3
|
206 /** no copies */
|
f@0
|
207 Wave( const Wave © ) = delete;
|
f@0
|
208 Wave & operator=(const Wave ©) = delete;
|
f@0
|
209
|
f@0
|
210
|
f@0
|
211 private:
|
f@0
|
212
|
f@0
|
213 const size_t mNumChunks;
|
f@0
|
214
|
f@0
|
215 std::vector<Chunk> mChunks;
|
f@0
|
216
|
f@0
|
217 Selection mSelection;
|
f@0
|
218
|
f@0
|
219 cinder::Color mColor;
|
f@0
|
220
|
f@0
|
221 float mFilterCoeff;
|
f@0
|
222
|
f@3
|
223 // cinder gl batch for batch drawing
|
f@0
|
224 ci::gl::BatchRef mChunkBatch;
|
f@0
|
225
|
f@0
|
226 };
|
f@0
|
227
|