f@0
|
1 #include "Wave.h"
|
f@0
|
2 #include "DrawInfo.h"
|
f@0
|
3
|
f@0
|
4
|
f@0
|
5 using namespace ci;
|
f@0
|
6
|
f@0
|
7 Wave::Wave( size_t numChunks, Color selectionColor ):
|
f@0
|
8 mNumChunks( numChunks ),
|
f@0
|
9 mSelection( this, selectionColor ),
|
f@0
|
10 mColor(Color(0.5f, 0.5f, 0.5f)),
|
f@0
|
11 mFilterCoeff( 1.0f )
|
f@0
|
12 {
|
f@0
|
13 mChunks.reserve( numChunks );
|
f@0
|
14
|
f@0
|
15 for ( size_t i = 0; i < numChunks; i++ ){
|
f@0
|
16 mChunks.emplace_back( i );
|
f@0
|
17 }
|
f@0
|
18
|
f@4
|
19 // init cinder batch drawing
|
f@0
|
20 auto lambert = gl::ShaderDef().color();
|
f@0
|
21 gl::GlslProgRef shader = gl::getStockShader( lambert );
|
f@0
|
22 mChunkBatch = gl::Batch::create( geom::Rect( ci::Rectf( 0, 0, Chunk::kWidth, 1 ) ), shader );
|
f@0
|
23 }
|
f@0
|
24
|
f@0
|
25 void Wave::reset( bool onlyChunks )
|
f@0
|
26 {
|
f@0
|
27 for (size_t i = 0; i < getSize(); i++){
|
f@0
|
28 mChunks[i].reset();
|
f@0
|
29 }
|
f@0
|
30
|
f@0
|
31 if (onlyChunks)
|
f@0
|
32 return;
|
f@0
|
33
|
f@0
|
34 mSelection.setToNull();
|
f@0
|
35 }
|
f@0
|
36
|
f@0
|
37
|
f@0
|
38 void Wave::setChunk(size_t index, float bottom, float top)
|
f@0
|
39 {
|
f@0
|
40 Chunk &c = mChunks[index];
|
f@0
|
41 c.setTop(top);
|
f@0
|
42 c.setBottom(bottom);
|
f@0
|
43 }
|
f@0
|
44
|
f@0
|
45 inline const Chunk & Wave::getChunk(size_t index)
|
f@0
|
46 {
|
f@0
|
47 return mChunks[index];
|
f@0
|
48 }
|
f@0
|
49
|
f@0
|
50 void Wave::update( double secondsPerChunk, const DrawInfo& di ) {
|
f@0
|
51 typedef std::map<int, Cursor>::iterator MapItr;
|
f@0
|
52
|
f@0
|
53
|
f@0
|
54 // update the cursor positions
|
f@0
|
55 double now = ci::app::getElapsedSeconds();
|
f@0
|
56 for (MapItr itr = mCursors.begin(); itr != mCursors.end(); ++itr){
|
f@0
|
57 if (mSelection.isNull()){
|
f@0
|
58 itr->second.pos = Cursor::kNoPosition;
|
f@0
|
59 }
|
f@0
|
60
|
f@0
|
61 if ( itr->second.pos == Cursor::kNoPosition )
|
f@0
|
62 continue;
|
f@0
|
63
|
f@0
|
64
|
f@0
|
65 double elapsed = now - itr->second.lastUpdate;
|
f@0
|
66
|
f@4
|
67 // A chunk of audio corresponds to a certain time according to sample rate.
|
f@4
|
68 // Use elapsed time to advance through chunks so that the cursor is animated
|
f@4
|
69 // and goes from start to end of the seleciton in the time span of the grain
|
f@0
|
70 itr->second.pos = mSelection.getStart() + int( elapsed / secondsPerChunk );
|
f@0
|
71
|
f@4
|
72 // check we don't go too far off
|
f@0
|
73 if (itr->second.pos > mSelection.getEnd()){
|
f@0
|
74 itr->second.pos = Cursor::kNoPosition;
|
f@0
|
75 }
|
f@0
|
76 }
|
f@0
|
77
|
f@0
|
78 // update chunks for animation
|
f@0
|
79 for ( auto &chunk : mChunks ){
|
f@0
|
80 chunk.update( di );
|
f@0
|
81 }
|
f@0
|
82
|
f@0
|
83 #ifdef USE_PARTICLES
|
f@0
|
84 mParticleController.updateParticles();
|
f@0
|
85 #endif
|
f@0
|
86
|
f@0
|
87 }
|
f@0
|
88
|
f@0
|
89 void Wave::draw( const DrawInfo& di ){
|
f@0
|
90
|
f@0
|
91
|
f@0
|
92 /* ########### draw the particles ########## */
|
f@0
|
93 #ifdef USE_PARTICLES
|
f@0
|
94 mParticleController.draw();
|
f@0
|
95 #endif
|
f@0
|
96
|
f@0
|
97 /* ########### draw the wave ########## */
|
f@0
|
98 /* scale the wave to fit the window */
|
f@0
|
99 gl::pushModelView();
|
f@0
|
100
|
f@0
|
101
|
f@0
|
102 const float wavePixelLen = ( mNumChunks * ( 2 + Chunk::kWidth ) );
|
f@3
|
103 /* scale the x-axis for the wave to fit the window precisely */
|
f@0
|
104 gl::scale( ((float)di.getWindowWidth() ) / wavePixelLen , 1.0f);
|
f@0
|
105 /* draw the chunks */
|
f@0
|
106 if (mSelection.isNull()){
|
f@0
|
107 /* no selection: all chunks the same color */
|
f@0
|
108 gl::color(mColor);
|
f@0
|
109 for (size_t i = 0; i < getSize(); i++){
|
f@0
|
110 mChunks[i].draw( di, mChunkBatch );
|
f@0
|
111 }
|
f@0
|
112 }
|
f@0
|
113 else{
|
f@0
|
114 // Selection not null
|
f@0
|
115 gl::color(this->mColor);
|
f@0
|
116
|
f@0
|
117 // update the array with cursor positions
|
f@0
|
118 mCursorsPos.clear();
|
f@0
|
119 for ( auto cursor : mCursors ){
|
f@0
|
120 mCursorsPos.push_back( cursor.second.pos );
|
f@0
|
121 }
|
f@0
|
122
|
f@0
|
123 gl::enableAlphaBlending();
|
f@0
|
124
|
f@0
|
125 const float selectionAlpha = 0.5f + mFilterCoeff * 0.5f;
|
f@0
|
126
|
f@0
|
127
|
f@0
|
128 for (size_t i = 0; i < getSize(); i++){
|
f@0
|
129 /* when in selection use selection color */
|
f@0
|
130
|
f@0
|
131 if (i == mSelection.getStart()){
|
f@0
|
132 /* draw the selection bar with a transparent selection color */
|
f@0
|
133 gl::color(mSelection.getColor().r, mSelection.getColor().g, mSelection.getColor().b, 0.5f);
|
f@0
|
134 mChunks[i].drawBar( di, mChunkBatch );
|
f@0
|
135
|
f@0
|
136 /* set the color to the selection */
|
f@0
|
137 gl::color(mSelection.getColor().r, mSelection.getColor().g, mSelection.getColor().b, selectionAlpha);
|
f@0
|
138 }
|
f@0
|
139
|
f@0
|
140 // check if one of the cursors is positioned in this chunk
|
f@0
|
141 if (std::find(mCursorsPos.begin(), mCursorsPos.end(),i) != mCursorsPos.end() ){
|
f@0
|
142 gl::color(CURSOR_CLR);
|
f@0
|
143 mChunks[i].draw( di, mChunkBatch );
|
f@0
|
144 gl::color(mSelection.getColor().r, mSelection.getColor().g, mSelection.getColor().b, selectionAlpha);
|
f@0
|
145 }
|
f@0
|
146 else{
|
f@0
|
147 /* just draw with current color */
|
f@0
|
148 mChunks[i].draw( di, mChunkBatch );
|
f@0
|
149 }
|
f@0
|
150
|
f@0
|
151 /* exit selection: go back to wave color */
|
f@0
|
152 if (i == mSelection.getEnd()){
|
f@0
|
153 /* draw the selection bar with a transparent selection color */
|
f@0
|
154 gl::color(mSelection.getColor().r, mSelection.getColor().g, mSelection.getColor().b, 0.5f);
|
f@0
|
155 mChunks[i].drawBar( di, mChunkBatch );
|
f@0
|
156 /* set the colo to the wave */
|
f@0
|
157 gl::color(this->mColor);
|
f@0
|
158 }
|
f@0
|
159 }
|
f@0
|
160 gl::disableAlphaBlending();
|
f@0
|
161 }
|
f@0
|
162
|
f@0
|
163
|
f@0
|
164 gl::popModelView();
|
f@0
|
165
|
f@0
|
166 }
|
f@0
|
167
|
f@0
|
168
|
f@0
|
169
|
f@0
|
170 //**************** Selection ***************//
|
f@0
|
171
|
f@0
|
172 Wave::Selection::Selection(Wave * w, Color color) :
|
f@0
|
173 mWave( w ),
|
f@0
|
174 mSelectionStart( 0 ),
|
f@0
|
175 mSelectionEnd( 0 ),
|
f@0
|
176 mColor( color ),
|
f@0
|
177 mParticleSpread( 1 )
|
f@0
|
178 {}
|
f@0
|
179
|
f@0
|
180
|
f@0
|
181 void Wave::Selection::setStart(size_t start) {
|
f@0
|
182
|
f@0
|
183 /* deselect the previous */
|
f@0
|
184 mWave->mChunks[mSelectionStart].setAsSelectionStart( false );
|
f@0
|
185 /* select the next */
|
f@0
|
186 mWave->mChunks[start].setAsSelectionStart( true );
|
f@0
|
187
|
f@0
|
188 mNull = false;
|
f@0
|
189
|
f@0
|
190 size_t size = getSize();
|
f@0
|
191
|
f@0
|
192 mSelectionStart = start;
|
f@0
|
193 mSelectionEnd = start + size - 1;
|
f@0
|
194 if ( mSelectionEnd > mWave->getSize() - 1 )
|
f@0
|
195 mSelectionEnd = mWave->getSize() - 1;
|
f@0
|
196
|
f@0
|
197 }
|
f@0
|
198
|
f@0
|
199 void Wave::Selection::setSize(size_t size) {
|
f@0
|
200
|
f@0
|
201 if ( size <= 0 ){
|
f@0
|
202 mNull = true;
|
f@0
|
203 return;
|
f@0
|
204 }
|
f@0
|
205
|
f@0
|
206 size -= 1;
|
f@0
|
207
|
f@0
|
208 // check boundaries: size cannot bring the selection end beyond the end of the wave
|
f@0
|
209 if ( mSelectionStart+size >= mWave->mNumChunks ){
|
f@0
|
210 size = mWave->mNumChunks - mSelectionStart - 1;
|
f@0
|
211 }
|
f@0
|
212
|
f@0
|
213 /* deselect the previous */
|
f@0
|
214 mWave->mChunks[mSelectionEnd].setAsSelectionEnd( false );
|
f@0
|
215
|
f@0
|
216 mSelectionEnd = mSelectionStart + size;
|
f@0
|
217 /* select the next */
|
f@0
|
218 mWave->mChunks[mSelectionEnd].setAsSelectionEnd( true );
|
f@0
|
219
|
f@0
|
220 mNull = false;
|
f@0
|
221 }
|
f@0
|
222
|
f@0
|
223
|
f@0
|
224 const cinder::Color Wave::CURSOR_CLR = Color(1.f, 1.f, 1.f);
|
f@0
|
225
|
f@0
|
226
|