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