f@5
|
1 /*
|
f@5
|
2
|
f@5
|
3 Copyright (C) 2016 Queen Mary University of London
|
f@5
|
4 Author: Fiore Martin
|
f@5
|
5
|
f@5
|
6 This file is part of Collidoscope.
|
f@5
|
7
|
f@5
|
8 Collidoscope is free software: you can redistribute it and/or modify
|
f@5
|
9 it under the terms of the GNU General Public License as published by
|
f@5
|
10 the Free Software Foundation, either version 3 of the License, or
|
f@5
|
11 (at your option) any later version.
|
f@5
|
12
|
f@5
|
13 This program is distributed in the hope that it will be useful,
|
f@5
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@5
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@5
|
16 GNU General Public License for more details.
|
f@5
|
17
|
f@5
|
18 You should have received a copy of the GNU General Public License
|
f@5
|
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@5
|
20 */
|
f@5
|
21
|
f@0
|
22 #include "cinder/app/App.h"
|
f@0
|
23 #include "cinder/app/RendererGl.h"
|
f@0
|
24 #include "cinder/gl/gl.h"
|
f@0
|
25 #include "cinder/Exception.h"
|
f@0
|
26
|
f@0
|
27
|
f@0
|
28 #include "Config.h"
|
f@0
|
29 #include "Wave.h"
|
f@0
|
30 #include "DrawInfo.h"
|
f@0
|
31 #include "Log.h"
|
f@0
|
32 #include "AudioEngine.h"
|
f@0
|
33 #include "Oscilloscope.h"
|
f@0
|
34 #include "Messages.h"
|
f@0
|
35 #include "MIDI.h"
|
f@0
|
36
|
f@0
|
37 using namespace ci;
|
f@0
|
38 using namespace ci::app;
|
f@0
|
39
|
f@0
|
40 using namespace std;
|
f@0
|
41
|
f@0
|
42
|
f@0
|
43 class CollidoscopeApp : public App {
|
f@0
|
44 public:
|
f@0
|
45
|
f@5
|
46 void setup() override;
|
f@0
|
47 void setupGraphics();
|
f@0
|
48
|
f@0
|
49 void receiveCommands();
|
f@0
|
50
|
f@5
|
51 void keyDown( KeyEvent event ) override;
|
f@5
|
52 void update() override;
|
f@5
|
53 void draw() override;
|
f@0
|
54 void resize() override;
|
f@0
|
55
|
f@5
|
56 Config mConfig;
|
f@0
|
57 collidoscope::MIDI mMIDI;
|
f@0
|
58 AudioEngine mAudioEngine;
|
f@5
|
59
|
f@0
|
60 array< shared_ptr< Wave >, NUM_WAVES > mWaves;
|
f@0
|
61 array< shared_ptr< DrawInfo >, NUM_WAVES > mDrawInfos;
|
f@0
|
62 array< shared_ptr< Oscilloscope >, NUM_WAVES > mOscilloscopes;
|
f@0
|
63 // buffers to read the wave messages as a new wave gets recorded
|
f@0
|
64 array< RecordWaveMsg*, NUM_WAVES> mRecordWaveMessageBuffers;
|
f@0
|
65 array< vector< CursorTriggerMsg >, NUM_WAVES > mCursorTriggerMessagesBuffers;
|
f@0
|
66
|
f@0
|
67 double mSecondsPerChunk;
|
f@0
|
68
|
f@0
|
69 ~CollidoscopeApp();
|
f@0
|
70
|
f@0
|
71 };
|
f@0
|
72
|
f@0
|
73
|
f@0
|
74 void CollidoscopeApp::setup()
|
f@0
|
75 {
|
f@0
|
76 hideCursor();
|
f@0
|
77 /* setup is logged: setup steps and errors */
|
f@0
|
78
|
f@0
|
79 /*try {
|
f@0
|
80 mConfig.loadFromFile( "./collidoscope_config.xml" );
|
f@0
|
81 }
|
f@0
|
82 catch ( const Exception &e ){
|
f@0
|
83 logError( string("Exception loading config from file:") + e.what() );
|
f@0
|
84 }*/
|
f@0
|
85
|
f@0
|
86 // setup buffers to read messages from audio thread
|
f@0
|
87 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
88 mRecordWaveMessageBuffers[i] = new RecordWaveMsg[mConfig.getNumChunks()];
|
f@0
|
89 mCursorTriggerMessagesBuffers[i].reserve( mConfig.getCursorTriggerMessageBufSize() );
|
f@0
|
90 }
|
f@0
|
91
|
f@0
|
92 mAudioEngine.setup( mConfig );
|
f@0
|
93
|
f@0
|
94 setupGraphics();
|
f@0
|
95
|
f@0
|
96 mSecondsPerChunk = mConfig.getWaveLen() / mConfig.getNumChunks();
|
f@0
|
97
|
f@0
|
98 try {
|
f@0
|
99 mMIDI.setup( mConfig );
|
f@0
|
100 }
|
f@0
|
101 catch ( const collidoscope::MIDIException &e ){
|
f@0
|
102 logError( string( "Exception opening MIDI input device: " ) + e.getMessage() );
|
f@0
|
103 }
|
f@0
|
104
|
f@0
|
105 }
|
f@0
|
106
|
f@0
|
107 void CollidoscopeApp::setupGraphics()
|
f@0
|
108 {
|
f@0
|
109 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
110
|
f@0
|
111 mDrawInfos[i] = make_shared< DrawInfo >( i );
|
f@0
|
112 mWaves[i] = make_shared< Wave >(mConfig.getNumChunks(), mConfig.getWaveSelectionColor(i) );
|
f@0
|
113 mOscilloscopes[i] = make_shared< Oscilloscope >( mAudioEngine.getAudioOutputBuffer( i ).getNumFrames() / mConfig.getOscilloscopeNumPointsDivider() );
|
f@0
|
114
|
f@0
|
115 }
|
f@0
|
116 }
|
f@0
|
117
|
f@0
|
118 void CollidoscopeApp::keyDown( KeyEvent event )
|
f@0
|
119 {
|
f@0
|
120 char c = event.getChar();
|
f@0
|
121
|
f@0
|
122 switch (c){
|
f@0
|
123 case 'r' :
|
f@0
|
124 mAudioEngine.record( 0 );
|
f@0
|
125 mAudioEngine.record( 1 );
|
f@0
|
126 break;
|
f@0
|
127
|
f@0
|
128 case 'w': {
|
f@0
|
129 mWaves[0]->getSelection().setSize(mWaves[0]->getSelection().getSize() + 1);
|
f@0
|
130
|
f@0
|
131 size_t numSelectionChunks = mWaves[0]->getSelection().getSize();
|
f@0
|
132 // how many samples in one selection ?
|
f@0
|
133 size_t selectionSize = numSelectionChunks * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks());
|
f@0
|
134
|
f@0
|
135 mAudioEngine.setSelectionSize(0, selectionSize);
|
f@0
|
136 };
|
f@0
|
137 break;
|
f@0
|
138
|
f@0
|
139 case 'e': {
|
f@0
|
140 mWaves[1]->getSelection().setSize(mWaves[1]->getSelection().getSize() + 1);
|
f@0
|
141
|
f@0
|
142 size_t numSelectionChunks = mWaves[1]->getSelection().getSize();
|
f@0
|
143 // how many samples in one selection ?
|
f@0
|
144 size_t selectionSize = numSelectionChunks * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks());
|
f@0
|
145
|
f@0
|
146 mAudioEngine.setSelectionSize(1, selectionSize);
|
f@0
|
147 };
|
f@0
|
148 break;
|
f@0
|
149
|
f@0
|
150 case 's': {
|
f@0
|
151
|
f@0
|
152 mWaves[0]->getSelection().setSize( mWaves[0]->getSelection().getSize() - 1 );
|
f@0
|
153
|
f@0
|
154 size_t selectionSize = mWaves[0]->getSelection().getSize() *(mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks());
|
f@0
|
155 mAudioEngine.setSelectionSize( 0, selectionSize );
|
f@0
|
156 };
|
f@0
|
157 break;
|
f@0
|
158
|
f@0
|
159 case 'd': {
|
f@0
|
160
|
f@0
|
161 for( size_t waveIdx = 0; waveIdx < NUM_WAVES; waveIdx++){
|
f@0
|
162 size_t selectionStart = mWaves[waveIdx]->getSelection().getStart();
|
f@0
|
163 mWaves[waveIdx]->getSelection().setStart( selectionStart + 1 );
|
f@0
|
164
|
f@0
|
165 selectionStart = mWaves[waveIdx]->getSelection().getStart();
|
f@0
|
166 mAudioEngine.setSelectionStart( waveIdx, selectionStart * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks()) );
|
f@0
|
167 }
|
f@0
|
168 };
|
f@0
|
169
|
f@0
|
170 break;
|
f@0
|
171
|
f@0
|
172 case 'a': {
|
f@0
|
173 size_t selectionStart = mWaves[0]->getSelection().getStart();
|
f@0
|
174
|
f@0
|
175 if ( selectionStart == 0 )
|
f@0
|
176 return;
|
f@0
|
177
|
f@0
|
178 mWaves[0]->getSelection().setStart( selectionStart - 1 );
|
f@0
|
179
|
f@0
|
180 selectionStart = mWaves[0]->getSelection().getStart();
|
f@0
|
181
|
f@0
|
182 mAudioEngine.setSelectionStart( 0, selectionStart * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks()) );
|
f@0
|
183 };
|
f@0
|
184 break;
|
f@0
|
185
|
f@0
|
186
|
f@0
|
187 case 'p':
|
f@0
|
188
|
f@0
|
189 mWaves[0]->setCursorPos( 4, mWaves[0]->getSelection().getStart(), *mDrawInfos[0] ) ;
|
f@0
|
190 break;
|
f@0
|
191
|
f@0
|
192 case 'f':
|
f@0
|
193 setFullScreen( !isFullScreen() );
|
f@0
|
194 break;
|
f@0
|
195
|
f@0
|
196 case ' ': {
|
f@0
|
197 static bool isOn = false;
|
f@0
|
198 isOn = !isOn;
|
f@0
|
199 if ( isOn ){
|
f@0
|
200 mAudioEngine.loopOn( 0 );
|
f@0
|
201 mAudioEngine.loopOn( 1 );
|
f@0
|
202 }
|
f@0
|
203 else{
|
f@0
|
204 mAudioEngine.loopOff( 0 );
|
f@0
|
205 mAudioEngine.loopOff( 1 );
|
f@0
|
206 }
|
f@0
|
207 };
|
f@0
|
208 break;
|
f@0
|
209
|
f@5
|
210 case 'm' :
|
f@5
|
211 mAudioEngine.setGrainDurationCoeff(0, 8);
|
f@5
|
212 break;
|
f@0
|
213
|
f@0
|
214 case 'n': {
|
f@0
|
215 mAudioEngine.setGrainDurationCoeff( 0, 1 );
|
f@0
|
216 };
|
f@0
|
217 break;
|
f@0
|
218
|
f@0
|
219 case '9': {
|
f@0
|
220 int c = mWaves[0]->getSelection().getParticleSpread();
|
f@0
|
221 if ( c == 1 )
|
f@0
|
222 return;
|
f@0
|
223 else
|
f@0
|
224 c -= 1;
|
f@0
|
225
|
f@0
|
226 mAudioEngine.setGrainDurationCoeff( 0, c );
|
f@0
|
227 mWaves[0]->getSelection().setParticleSpread( float( c ) );
|
f@0
|
228 mAudioEngine.setGrainDurationCoeff( 1, c );
|
f@0
|
229 mWaves[1]->getSelection().setParticleSpread( float( c ) );
|
f@0
|
230 }; break;
|
f@0
|
231
|
f@0
|
232 case '0': {
|
f@0
|
233 int c = mWaves[0]->getSelection().getParticleSpread();
|
f@0
|
234 if ( c == 8 )
|
f@0
|
235 return;
|
f@0
|
236 else
|
f@0
|
237 c += 1;
|
f@0
|
238
|
f@0
|
239 mAudioEngine.setGrainDurationCoeff( 0, c );
|
f@0
|
240 mWaves[0]->getSelection().setParticleSpread( float( c ) );
|
f@0
|
241 }; break;
|
f@0
|
242
|
f@0
|
243 }
|
f@0
|
244
|
f@0
|
245 }
|
f@0
|
246
|
f@0
|
247 void CollidoscopeApp::update()
|
f@0
|
248 {
|
f@0
|
249 // check incoming commands
|
f@0
|
250 receiveCommands();
|
f@0
|
251
|
f@0
|
252 // check new wave chunks from recorder buffer
|
f@0
|
253 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
254 size_t availableRead = mAudioEngine.getRecordWaveAvailable( i );
|
f@0
|
255 mAudioEngine.readRecordWave( i, mRecordWaveMessageBuffers[i], availableRead );
|
f@0
|
256
|
f@0
|
257 for ( size_t msgIndex = 0; msgIndex < availableRead; msgIndex++ ){
|
f@0
|
258 const RecordWaveMsg & msg = mRecordWaveMessageBuffers[i][msgIndex];
|
f@0
|
259
|
f@0
|
260 if ( msg.cmd == Command::WAVE_CHUNK ){
|
f@0
|
261 mWaves[i]->setChunk( msg.index, msg.arg1, msg.arg2 );
|
f@0
|
262 }
|
f@0
|
263 else if ( msg.cmd == Command::WAVE_START ){
|
f@0
|
264 mWaves[i]->reset( true ); // reset only chunks but leave selection
|
f@0
|
265 }
|
f@0
|
266
|
f@0
|
267 }
|
f@0
|
268 }
|
f@0
|
269
|
f@0
|
270 // check if new cursors have been triggered
|
f@0
|
271 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
272
|
f@0
|
273 mAudioEngine.checkCursorTriggers( i, mCursorTriggerMessagesBuffers[i] );
|
f@0
|
274 for ( auto & trigger : mCursorTriggerMessagesBuffers[i] ){
|
f@0
|
275 const int nodeID = trigger.synthID;
|
f@0
|
276
|
f@0
|
277 switch ( trigger.cmd ){
|
f@0
|
278
|
f@0
|
279 case Command::TRIGGER_UPDATE: {
|
f@0
|
280 mWaves[i]->setCursorPos( nodeID, mWaves[i]->getSelection().getStart(), *mDrawInfos[i] );
|
f@0
|
281 };
|
f@0
|
282 break;
|
f@0
|
283
|
f@0
|
284 case Command::TRIGGER_END: {
|
f@0
|
285 mWaves[i]->removeCursor( nodeID );
|
f@0
|
286 };
|
f@0
|
287 break;
|
f@0
|
288
|
f@0
|
289 }
|
f@0
|
290
|
f@0
|
291 }
|
f@0
|
292 mCursorTriggerMessagesBuffers[i].clear();
|
f@0
|
293 }
|
f@0
|
294
|
f@0
|
295 // update cursors
|
f@0
|
296 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
297 mWaves[i]->update( mSecondsPerChunk, *mDrawInfos[i] );
|
f@0
|
298 }
|
f@0
|
299
|
f@0
|
300 // update oscilloscope
|
f@0
|
301
|
f@0
|
302 for ( size_t i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
303 const audio::Buffer &audioOutBuffer = mAudioEngine.getAudioOutputBuffer( i );
|
f@0
|
304 // one oscilloscope sample
|
f@0
|
305
|
f@0
|
306 for ( size_t j = 0; j < mOscilloscopes[i]->getNumPoints(); j++ ){
|
f@0
|
307 mOscilloscopes[i]->setPoint( j, audioOutBuffer.getData()[j], *mDrawInfos[i] );
|
f@0
|
308 }
|
f@0
|
309 }
|
f@0
|
310
|
f@0
|
311
|
f@0
|
312
|
f@0
|
313 }
|
f@0
|
314
|
f@0
|
315 void CollidoscopeApp::draw()
|
f@0
|
316 {
|
f@5
|
317 gl::clear( Color( 0, 0, 0 ) );
|
f@0
|
318
|
f@0
|
319 for ( int i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
320 if ( i == 1 ){
|
f@0
|
321 /* for the upper wave flip the x over the center of the screen which is
|
f@0
|
322 the composition of rotate on the y-axis and translate by -screenwidth*/
|
f@0
|
323 gl::pushModelMatrix();
|
f@0
|
324 gl::rotate( float(M_PI), ci::vec3( 0, 1, 0 ) );
|
f@0
|
325 gl::translate( float( -getWindowWidth() ), 0.0f );
|
f@0
|
326 mOscilloscopes[i]->draw();
|
f@0
|
327 mWaves[i]->draw( *mDrawInfos[i] );
|
f@0
|
328 gl::popModelMatrix();
|
f@0
|
329 }
|
f@0
|
330 else{
|
f@0
|
331
|
f@0
|
332 mOscilloscopes[i]->draw();
|
f@0
|
333 mWaves[i]->draw( *mDrawInfos[i] );
|
f@0
|
334 }
|
f@0
|
335 }
|
f@0
|
336 }
|
f@0
|
337
|
f@0
|
338 void CollidoscopeApp::resize()
|
f@0
|
339 {
|
f@0
|
340 App::resize();
|
f@0
|
341
|
f@0
|
342 for ( int i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
343 // reset the drawing information with the new windows size and same shrink factor
|
f@0
|
344 mDrawInfos[i]->reset( getWindow()->getBounds(), 3.0f / 5.0f );
|
f@0
|
345
|
f@0
|
346 /* reset the oscilloscope points to zero */
|
f@0
|
347 for ( int j = 0; j < mOscilloscopes[i]->getNumPoints(); j++ ){
|
f@0
|
348 mOscilloscopes[i]->setPoint(j, 0.0f, *mDrawInfos[i] );
|
f@0
|
349 }
|
f@0
|
350 }
|
f@0
|
351 }
|
f@0
|
352
|
f@0
|
353
|
f@0
|
354
|
f@0
|
355 void CollidoscopeApp::receiveCommands()
|
f@0
|
356 {
|
f@0
|
357 // check new midi messages
|
f@0
|
358 static std::vector<collidoscope::MIDIMessage> midiMessages;
|
f@0
|
359 mMIDI.checkMessages( midiMessages );
|
f@0
|
360
|
f@0
|
361
|
f@0
|
362 for ( auto &m : midiMessages ){
|
f@0
|
363
|
f@0
|
364 const size_t waveIdx = mConfig.getWaveForMIDIChannel( m.getChannel() );
|
f@0
|
365 if ( waveIdx >= NUM_WAVES )
|
f@0
|
366 continue;
|
f@0
|
367
|
f@0
|
368 if ( m.getVoice() == collidoscope::MIDIMessage::Voice::eNoteOn ){
|
f@0
|
369 int midiNote = m.getData_1();
|
f@0
|
370 mAudioEngine.noteOn( waveIdx, midiNote );
|
f@0
|
371 }
|
f@0
|
372 else if ( m.getVoice() == collidoscope::MIDIMessage::Voice::eNoteOff ){
|
f@0
|
373 int midiNote = m.getData_1();
|
f@0
|
374 mAudioEngine.noteOff( waveIdx, midiNote );
|
f@0
|
375 }
|
f@0
|
376 else if ( m.getVoice() == collidoscope::MIDIMessage::Voice::ePitchBend ){
|
f@0
|
377 const uint16_t MSB = m.getData_2() << 7;
|
f@0
|
378 uint16_t value = m.getData_1(); // LSB
|
f@0
|
379
|
f@0
|
380 value |= MSB;
|
f@0
|
381
|
f@0
|
382
|
f@0
|
383 // value ranges from 0 to 1050. check boundaries in case sensor gives bad values
|
f@0
|
384 if ( value > 149 ){ // FIXME pareametrizer
|
f@0
|
385 continue;
|
f@0
|
386 }
|
f@0
|
387
|
f@0
|
388 size_t startChunk = value;
|
f@0
|
389
|
f@0
|
390 const size_t selectionSizeBeforeStartUpdate = mWaves[waveIdx]->getSelection().getSize();
|
f@0
|
391 mWaves[waveIdx]->getSelection().setStart( startChunk );
|
f@0
|
392
|
f@0
|
393 mAudioEngine.setSelectionStart( waveIdx, startChunk * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks()) );
|
f@0
|
394
|
f@0
|
395 const size_t newSelectionSize = mWaves[waveIdx]->getSelection().getSize();
|
f@0
|
396 if ( selectionSizeBeforeStartUpdate != newSelectionSize ){
|
f@0
|
397 mAudioEngine.setSelectionSize( waveIdx, newSelectionSize * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks()) );
|
f@0
|
398 }
|
f@0
|
399
|
f@0
|
400
|
f@0
|
401 }
|
f@0
|
402 else if ( m.getVoice() == collidoscope::MIDIMessage::Voice::eControlChange ){
|
f@0
|
403
|
f@0
|
404 switch ( m.getData_1() ){ //controller number
|
f@0
|
405 case 1: { // selection size
|
f@0
|
406 const size_t midiVal = m.getData_2();
|
f@0
|
407 size_t numSelectionChunks = ci::lmap<size_t>( midiVal, 0, 127, 1, mConfig.getMaxSelectionNumChunks() );
|
f@0
|
408
|
f@0
|
409 mWaves[waveIdx]->getSelection().setSize( numSelectionChunks );
|
f@0
|
410
|
f@0
|
411 // how many samples in one selection ?
|
f@5
|
412 size_t selectionSize = mWaves[waveIdx]->getSelection().getSize() * (mConfig.getWaveLen() * mAudioEngine.getSampleRate() / mConfig.getNumChunks());
|
f@0
|
413 mAudioEngine.setSelectionSize( waveIdx, selectionSize );
|
f@0
|
414
|
f@0
|
415 };
|
f@0
|
416 break;
|
f@0
|
417
|
f@0
|
418 case 4: { // loop on off
|
f@0
|
419 unsigned char midiVal = m.getData_2();
|
f@0
|
420
|
f@0
|
421 if ( midiVal > 0 )
|
f@0
|
422 mAudioEngine.loopOn( waveIdx );
|
f@0
|
423 else
|
f@0
|
424 mAudioEngine.loopOff( waveIdx );
|
f@0
|
425 };
|
f@0
|
426 break;
|
f@0
|
427
|
f@0
|
428 case 5: // trigger record
|
f@0
|
429 mAudioEngine.record( waveIdx );
|
f@0
|
430 break;
|
f@0
|
431
|
f@0
|
432 case 2: { // duration
|
f@0
|
433 const double midiVal = m.getData_2(); // 0-127
|
f@0
|
434 const double coeff = ci::lmap<double>( midiVal, 0.0, 127, 1.0, mConfig.getMaxGrainDurationCoeff() );
|
f@0
|
435 mAudioEngine.setGrainDurationCoeff( waveIdx, coeff );
|
f@0
|
436 mWaves[waveIdx]->getSelection().setParticleSpread( float( coeff ) );
|
f@0
|
437 };
|
f@0
|
438 break;
|
f@0
|
439
|
f@0
|
440 case 7: { // filter
|
f@0
|
441 const double midiVal = m.getData_2(); // 0-127
|
f@0
|
442 const double minCutoff = mConfig.getMinFilterCutoffFreq();
|
f@0
|
443 const double maxCutoff = mConfig.getMaxFilterCutoffFreq();
|
f@0
|
444 const double cutoff = pow( maxCutoff / 200., midiVal / 127.0 ) * minCutoff;
|
f@0
|
445 mAudioEngine.setFilterCutoff( waveIdx, cutoff );
|
f@0
|
446 const float alpha = ci::lmap<double>( midiVal, 0.0f, 127.0f, 0.f, 1.f );
|
f@0
|
447 mWaves[waveIdx]->setselectionAlpha( alpha );
|
f@0
|
448 };
|
f@0
|
449 break;
|
f@0
|
450
|
f@0
|
451
|
f@0
|
452
|
f@0
|
453 }
|
f@0
|
454 }
|
f@0
|
455 }
|
f@0
|
456
|
f@0
|
457 midiMessages.clear();
|
f@0
|
458 }
|
f@0
|
459
|
f@0
|
460
|
f@0
|
461
|
f@0
|
462 CollidoscopeApp::~CollidoscopeApp()
|
f@0
|
463 {
|
f@0
|
464 for ( int chan = 0; chan < NUM_WAVES; chan++ ){
|
f@0
|
465 /* delete the array for wave messages from audio thread */
|
f@0
|
466 delete[] mRecordWaveMessageBuffers[chan];
|
f@0
|
467 }
|
f@0
|
468 }
|
f@0
|
469
|
f@0
|
470 CINDER_APP( CollidoscopeApp, RendererGl, [] ( App::Settings *settings) {
|
f@0
|
471 settings->setWindowSize( 1920, 1080 );
|
f@0
|
472 settings->setMultiTouchEnabled( false );
|
f@0
|
473 settings->disableFrameRate();
|
f@0
|
474
|
f@0
|
475 } )
|