hydrogen 1.2.6
OscServer.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <QRegularExpression>
24
27
28#include <pthread.h>
29#include <unistd.h>
30
31//currently H2CORE_HAVE_OSC means: liblo is present..
32#if defined(H2CORE_HAVE_OSC) || _DOXYGEN_
33
34#include <lo/lo.h>
35#include <lo/lo_cpp.h>
36
38#include "core/OscServer.h"
40#include "core/EventQueue.h"
41#include "core/Hydrogen.h"
43#include "core/Basics/Song.h"
44#include "core/MidiAction.h"
45#include "core/IO/MidiCommon.h"
46
48
49
50QString OscServer::qPrettyPrint(lo_type type,void * data)
51{
52 QString formattedString;
53
54 typedef union {
55 int32_t i;
56 float f;
57 char c;
58 uint32_t nl;
59 } h2_pcast32;
60
61 typedef union {
62 int64_t i;
63 double f;
64 uint64_t nl;
65 } h2_pcast64;
66
67
68 h2_pcast32 val32 = {0};
69 h2_pcast64 val64 = {0};
70 int size;
71
72 size = lo_arg_size(type, data);
73 if (size == 4 || type == LO_BLOB) {
74 val32.nl = *(int32_t *)data;
75 } else if (size == 8) {
76 val64.nl = *(int64_t *)data;
77 } else {
78 //error case
79 formattedString = QString("Unhandled size: %1").arg(size);
80
81 return formattedString;
82 }
83
84 switch (type) {
85 case LO_INT32:
86 formattedString = QString("%1").arg(val32.i);
87 break;
88
89 case LO_FLOAT:
90 formattedString = QString("%1").arg(val32.f);
91 break;
92
93 case LO_STRING:
94 formattedString = QString("%1").arg( (char *) data );
95 break;
96
97 case LO_BLOB:
98 //not supported by Hydrogen
99 formattedString = QString("BLOB");
100 break;
101
102 case LO_INT64:
103 formattedString = QString("%1").arg(val64.i);
104 break;
105
106 case LO_DOUBLE:
107 formattedString = QString("%1").arg(val64.f);
108 break;
109
110 case LO_SYMBOL:
111 formattedString = QString("%1").arg( (char *) data );
112 break;
113
114 case LO_CHAR:
115 formattedString = QString("%1").arg( QLatin1Char((char) val32.c ));
116 break;
117
118 case LO_MIDI:
119 //not supported by Hydrogen
120 formattedString = QString("MIDI");
121 break;
122
123 case LO_TRUE:
124 formattedString = QString("#T");
125 break;
126
127 case LO_FALSE:
128 formattedString = QString("#F");
129 break;
130
131 case LO_NIL:
132 formattedString = QString("#NIL");
133 break;
134
135 case LO_INFINITUM:
136 formattedString = QString("#INF");
137 break;
138
139 case LO_TIMETAG:
140 default:
141 formattedString = QString("Unhandled type:").arg(type);
142 break;
143 }
144
145 return formattedString;
146
147}
148
149/* catch any incoming messages and display them. returning 1 means that the
150 * message has not been fully handled and the server should try other methods */
152 const char * types,
153 lo_arg ** argv,
154 int argc,
155 lo_message data,
156 void * user_data) {
157
158 QString sSummary = QString( "Incoming OSC Message for path [%1]" ).arg( path );
159 for ( int ii = 0; ii < argc; ii++) {
160 QString formattedArgument = qPrettyPrint( (lo_type)types[ii], argv[ii] );
161 sSummary.append( QString( ", arg. %1: [%2, %3]" )
162 .arg( ii ).arg( types[ ii ] ).arg( formattedArgument ) );
163 }
164
165 INFOLOG( sSummary );
166
167 return 1;
168}
169
170int OscServer::generic_handler(const char * path,
171 const char * types,
172 lo_arg ** argv,
173 int argc,
174 lo_message data,
175 void * user_data)
176{
177 auto pHydrogen = H2Core::Hydrogen::get_instance();
178 auto pController = pHydrogen->getCoreActionController();
179 auto pSong = pHydrogen->getSong();
180
181 if ( pSong == nullptr ) {
182 ERRORLOG( "No song set yet" );
183 return 1;
184 }
185
186 bool bMessageProcessed = false;
187
188 const int nNumberOfStrips = pSong->getInstrumentList()->size();
189
190 //First we're trying to map TouchOSC messages from multi-fader widgets
191 const QString oscPath( path );
192
193 QRegularExpression rxStripVol(
194 QRegularExpression::anchoredPattern(
195 "/Hydrogen/STRIP_VOLUME_ABSOLUTE/(\\d+)" ) );
196 rxStripVol.setPatternOptions(
197 QRegularExpression::UseUnicodePropertiesOption );
198 const auto rxStripVolMatch = rxStripVol.match( oscPath );
199 if ( rxStripVolMatch.hasMatch() && argc == 1 ) {
200 const int nStrip = rxStripVolMatch.captured( 1 ).toInt() -1;
201 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
202 STRIP_VOLUME_ABSOLUTE_Handler( nStrip , argv[0]->f );
203 bMessageProcessed = true;
204 }
205 else {
206 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
207 .arg( nStrip + 1 ).arg( 1 )
208 .arg( nNumberOfStrips ) );
209 }
210 }
211
212 QRegularExpression rxStripVolRel(
213 QRegularExpression::anchoredPattern(
214 "/Hydrogen/STRIP_VOLUME_RELATIVE/(\\d+)" ) );
215 rxStripVolRel.setPatternOptions(
216 QRegularExpression::UseUnicodePropertiesOption );
217 const auto rxStripVolRelMatch = rxStripVolRel.match( oscPath );
218 if ( rxStripVolRelMatch.hasMatch() && argc == 1 ) {
219 const int nStrip = rxStripVolRelMatch.captured( 1 ).toInt() - 1;
220 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
221 STRIP_VOLUME_RELATIVE_Handler( QString::number( nStrip ),
222 QString::number( argv[0]->f, 'f', 0 ) );
223 bMessageProcessed = true;
224 }
225 else {
226 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
227 .arg( nStrip + 1 ).arg( 1 )
228 .arg( nNumberOfStrips ) );
229 }
230 }
231
232 QRegularExpression rxStripPanAbs(
233 QRegularExpression::anchoredPattern(
234 "/Hydrogen/PAN_ABSOLUTE/(\\d+)" ) );
235 rxStripPanAbs.setPatternOptions(
236 QRegularExpression::UseUnicodePropertiesOption );
237 const auto rxStripPanAbsMatch = rxStripPanAbs.match( oscPath );
238 if ( rxStripPanAbsMatch.hasMatch() && argc == 1 ) {
239 const int nStrip = rxStripPanAbsMatch.captured( 1 ).toInt() - 1;
240 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
241 INFOLOG( QString( "processing message as changing pan of strip [%1] in absolute numbers" )
242 .arg( nStrip ) );
243 pController->setStripPan( nStrip, argv[0]->f, false );
244 bMessageProcessed = true;
245 }
246 else {
247 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
248 .arg( nStrip + 1 ).arg( 1 )
249 .arg( nNumberOfStrips ) );
250 }
251 }
252
253 QRegularExpression rxStripPanAbsSym(
254 QRegularExpression::anchoredPattern(
255 "/Hydrogen/PAN_ABSOLUTE_SYM/(\\d+)" ) );
256 rxStripPanAbsSym.setPatternOptions(
257 QRegularExpression::UseUnicodePropertiesOption );
258 const auto rxStripPanAbsSymMatch = rxStripPanAbsSym.match( oscPath );
259 if ( rxStripPanAbsSymMatch.hasMatch() && argc == 1 ) {
260 const int nStrip = rxStripPanAbsSymMatch.captured( 1 ).toInt() - 1;
261 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
262 INFOLOG( QString( "processing message as changing pan of strip [%1] in symmetric, absolute numbers" )
263 .arg( nStrip ) );
264 pController->setStripPanSym( nStrip, argv[0]->f, false );
265 bMessageProcessed = true;
266 }
267 else {
268 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
269 .arg( nStrip + 1 ).arg( 1 )
270 .arg( nNumberOfStrips ) );
271 }
272 }
273
274 QRegularExpression rxStripPanRel(
275 QRegularExpression::anchoredPattern(
276 "/Hydrogen/PAN_RELATIVE/(\\d+)" ) );
277 rxStripPanRel.setPatternOptions(
278 QRegularExpression::UseUnicodePropertiesOption );
279 const auto rxStripPanRelMatch = rxStripPanRel.match( oscPath );
280 if ( rxStripPanRelMatch.hasMatch() && argc == 1 ) {
281 const int nStrip = rxStripPanRelMatch.captured( 1 ).toInt() - 1;
282 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
283 INFOLOG( QString( "processing message as changing pan of strip [%1] in relative numbers" )
284 .arg( nStrip ) );
285 std::shared_ptr<Action> pAction = std::make_shared<Action>("PAN_RELATIVE");
286 pAction->setParameter1( QString::number( nStrip ) );
287 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ) );
289 bMessageProcessed = true;
290 }
291 else {
292 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
293 .arg( nStrip + 1 ).arg( 1 )
294 .arg( nNumberOfStrips ) );
295 }
296 }
297
298 QRegularExpression rxStripFilterCutoffAbs(
299 QRegularExpression::anchoredPattern(
300 "/Hydrogen/FILTER_CUTOFF_LEVEL_ABSOLUTE/(\\d+)" ) );
301 rxStripFilterCutoffAbs.setPatternOptions(
302 QRegularExpression::UseUnicodePropertiesOption );
303 const auto rxStripFilterCutoffAbsMatch =
304 rxStripFilterCutoffAbs.match( oscPath );
305 if ( rxStripFilterCutoffAbsMatch.hasMatch() && argc == 1 ) {
306 const int nStrip = rxStripFilterCutoffAbsMatch.captured( 1 ).toInt() - 1;
307 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
309 QString::number( nStrip ), QString::number( argv[0]->f, 'f', 0 ) );
310 bMessageProcessed = true;
311 }
312 else {
313 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
314 .arg( nStrip + 1 ).arg( 1 )
315 .arg( nNumberOfStrips ) );
316 }
317 }
318
319 QRegularExpression rxStripMute(
320 QRegularExpression::anchoredPattern(
321 "/Hydrogen/STRIP_MUTE_TOGGLE/(\\d+)" ) );
322 rxStripMute.setPatternOptions(
323 QRegularExpression::UseUnicodePropertiesOption );
324 const auto rxStripMuteMatch = rxStripMute.match( oscPath );
325 if ( rxStripMuteMatch.hasMatch() && argc <= 1 ) {
326 const int nStrip = rxStripMuteMatch.captured( 1 ).toInt() - 1;
327 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
328 INFOLOG( QString( "processing message as toggling mute of strip [%1]" )
329 .arg( nStrip ) );
330 pController->toggleStripIsMuted( nStrip );
331 bMessageProcessed = true;
332 }
333 else {
334 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
335 .arg( nStrip + 1 ).arg( 1 )
336 .arg( nNumberOfStrips ) );
337 }
338 }
339
340 QRegularExpression rxStripSolo(
341 QRegularExpression::anchoredPattern(
342 "/Hydrogen/STRIP_SOLO_TOGGLE/(\\d+)" ) );
343 rxStripSolo.setPatternOptions(
344 QRegularExpression::UseUnicodePropertiesOption );
345 const auto rxStripSoloMatch = rxStripSolo.match( oscPath );
346 if ( rxStripSoloMatch.hasMatch() && argc <= 1 ) {
347 const int nStrip = rxStripSoloMatch.captured( 1 ).toInt() - 1;
348 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
349 INFOLOG( QString( "processing message as toggling solo of strip [%1]" )
350 .arg( nStrip ) );
351 pController->toggleStripIsSoloed( nStrip );
352 bMessageProcessed = true;
353 }
354 else {
355 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
356 .arg( nStrip + 1 ).arg( 1 )
357 .arg( nNumberOfStrips ) );
358 }
359 }
360
361 if ( ! bMessageProcessed ) {
362 ERRORLOG( "No matching handler found" );
363 }
364
365 // Returning 1 means that the message has not been fully handled
366 // and the server should try other methods.
367 return 1;
368}
369
370
371
373{
374 m_pPreferences = pPreferences;
375
376 if ( m_pPreferences->getOscServerEnabled() ) {
377 int nPort;
378 if ( m_pPreferences->m_nOscTemporaryPort != -1 ) {
379 nPort = m_pPreferences->m_nOscTemporaryPort;
380 } else {
381 nPort = m_pPreferences->getOscServerPort();
382 }
383
384 m_pServerThread = new lo::ServerThread( nPort );
385
386 // If there is already another service registered to the same
387 // port, the OSC server is not valid an can not be started.
388 if ( ! m_pServerThread->is_valid() ) {
389 delete m_pServerThread;
390
391 // Instead, let the liblo library choose a working
392 // port on their own (nullptr argument).
393 m_pServerThread = new lo::ServerThread( nullptr );
394
395 const int nTmpPort = m_pServerThread->port();
396
397 ERRORLOG( QString("Could not start OSC server on port %1, using port %2 instead.")
398 .arg( nPort ).arg( nTmpPort ) );
399
400 m_pPreferences->m_nOscTemporaryPort = nTmpPort;
401
402 H2Core::EventQueue::get_instance()->push_event(
403 H2Core::EVENT_ERROR, H2Core::Hydrogen::OSC_CANNOT_CONNECT_TO_PORT );
404 }
405 }
406 else {
407 m_pServerThread = nullptr;
408 }
409}
410
412
413 for (std::list<lo_address>::iterator it=m_pClientRegistry.begin(); it != m_pClientRegistry.end(); ++it){
414 lo_address_free( *it );
415 }
416
417 delete m_pServerThread;
418
419 __instance = nullptr;
420}
421
423{
424 if( __instance == nullptr ) {
425 __instance = new OscServer( pPreferences );
426 }
427}
428
429// -------------------------------------------------------------------
430// Handler functions
431
432void OscServer::PLAY_Handler(lo_arg **argv,int i)
433{
434 INFOLOG( "processing message" );
435 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY");
437
438 // Null song handling done in MidiActionManager.
439 pActionManager->handleAction( pAction );
440}
441
442void OscServer::PLAY_STOP_TOGGLE_Handler(lo_arg **argv,int i)
443{
444 INFOLOG( "processing message" );
445 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY/STOP_TOGGLE");
447
448 // Null song handling done in MidiActionManager.
449 pActionManager->handleAction( pAction );
450}
451
453{
454 INFOLOG( "processing message" );
455 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY/PAUSE_TOGGLE");
457
458 // Null song handling done in MidiActionManager.
459 pActionManager->handleAction( pAction );
460}
461
462void OscServer::STOP_Handler(lo_arg **argv,int i)
463{
464 INFOLOG( "processing message" );
465 std::shared_ptr<Action> pAction = std::make_shared<Action>("STOP");
467
468 // Null song handling done in MidiActionManager.
469 pActionManager->handleAction( pAction );
470}
471
472void OscServer::PAUSE_Handler(lo_arg **argv,int i)
473{
474 INFOLOG( "processing message" );
475 std::shared_ptr<Action> pAction = std::make_shared<Action>("PAUSE");
477
478 // Null song handling done in MidiActionManager.
479 pActionManager->handleAction( pAction );
480}
481
482void OscServer::RECORD_READY_Handler(lo_arg **argv,int i)
483{
484 INFOLOG( "processing message" );
485 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_READY");
487
488 // Null song handling done in MidiActionManager.
489 pActionManager->handleAction( pAction );
490}
491
493{
494 INFOLOG( "processing message" );
495 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD/STROBE_TOGGLE");
497
498 // Null song handling done in MidiActionManager.
499 pActionManager->handleAction( pAction );
500}
501
502void OscServer::RECORD_STROBE_Handler(lo_arg **argv,int i)
503{
504 INFOLOG( "processing message" );
505 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_STROBE");
507
508 // Null song handling done in MidiActionManager.
509 pActionManager->handleAction( pAction );
510}
511
512void OscServer::RECORD_EXIT_Handler(lo_arg **argv,int i)
513{
514 INFOLOG( "processing message" );
515 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_EXIT");
517
518 // Null song handling done in MidiActionManager.
519 pActionManager->handleAction( pAction );
520}
521
522void OscServer::MUTE_Handler(lo_arg **argv,int i)
523{
524 INFOLOG( "processing message" );
525 std::shared_ptr<Action> pAction = std::make_shared<Action>("MUTE");
527
528 // Null song handling done in MidiActionManager.
529 pActionManager->handleAction( pAction );
530}
531
532void OscServer::UNMUTE_Handler(lo_arg **argv,int i)
533{
534 INFOLOG( "processing message" );
535 std::shared_ptr<Action> pAction = std::make_shared<Action>("UNMUTE");
537
538 // Null song handling done in MidiActionManager.
539 pActionManager->handleAction( pAction );
540}
541
542void OscServer::MUTE_TOGGLE_Handler(lo_arg **argv,int i)
543{
544 INFOLOG( "processing message" );
545 std::shared_ptr<Action> pAction = std::make_shared<Action>("MUTE_TOGGLE");
547
548 // Null song handling done in MidiActionManager.
549 pActionManager->handleAction( pAction );
550}
551
552void OscServer::NEXT_BAR_Handler(lo_arg **argv,int i)
553{
554 INFOLOG( "processing message" );
555 std::shared_ptr<Action> pAction = std::make_shared<Action>(">>_NEXT_BAR");
557
558 // Null song handling done in MidiActionManager.
559 pActionManager->handleAction( pAction );
560}
561
562void OscServer::PREVIOUS_BAR_Handler(lo_arg **argv,int i)
563{
564 INFOLOG( "processing message" );
565 std::shared_ptr<Action> pAction = std::make_shared<Action>("<<_PREVIOUS_BAR");
567
568 // Null song handling done in MidiActionManager.
569 pActionManager->handleAction( pAction );
570}
571
572void OscServer::BPM_Handler(lo_arg **argv,int i)
573{
574 INFOLOG( "processing message" );
575 auto pHydrogen = H2Core::Hydrogen::get_instance();
576 auto pAudioEngine = pHydrogen->getAudioEngine();
577
578 float fNewBpm = argv[0]->f;
579 fNewBpm = std::clamp( fNewBpm, static_cast<float>(MIN_BPM),
580 static_cast<float>(MAX_BPM) );
581
582 pAudioEngine->lock( RIGHT_HERE );
583 pAudioEngine->setNextBpm( fNewBpm );
584 pAudioEngine->unlock();
585
586 pHydrogen->getSong()->setBpm( fNewBpm );
587
588 pHydrogen->setIsModified( true );
589
591}
592
593void OscServer::BPM_INCR_Handler(lo_arg **argv,int i)
594{
595 INFOLOG( "processing message" );
596 std::shared_ptr<Action> pAction = std::make_shared<Action>("BPM_INCR");
598
599 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ));
600
601 // Null song handling done in MidiActionManager.
602 pActionManager->handleAction( pAction );
603}
604
605void OscServer::BPM_DECR_Handler(lo_arg **argv,int i)
606{
607 INFOLOG( "processing message" );
608 std::shared_ptr<Action> pAction = std::make_shared<Action>("BPM_DECR");
610
611 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ));
612
613 // Null song handling done in MidiActionManager.
614 pActionManager->handleAction( pAction );
615}
616
618{
619 INFOLOG( "processing message" );
621 H2Core::CoreActionController* pController = pHydrogen->getCoreActionController();
622
623 // Null song handling done in MidiActionManager.
624 pController->setMasterVolume( argv[0]->f );
625}
626
628{
629 INFOLOG( "processing message" );
630 std::shared_ptr<Action> pAction = std::make_shared<Action>("MASTER_VOLUME_RELATIVE");
631 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ));
633
634 // Null song handling done in MidiActionManager.
635 pActionManager->handleAction( pAction );
636}
637
638void OscServer::STRIP_VOLUME_ABSOLUTE_Handler(int param1, float param2)
639{
640 INFOLOG( "processing message" );
642 H2Core::CoreActionController* pController = pHydrogen->getCoreActionController();
643
644 // Null song handling done in MidiActionManager.
645 pController->setStripVolume( param1, param2, false );
646}
647
648void OscServer::STRIP_VOLUME_RELATIVE_Handler(QString param1, QString param2)
649{
650 INFOLOG( "processing message" );
651 std::shared_ptr<Action> pAction = std::make_shared<Action>("STRIP_VOLUME_RELATIVE");
652 pAction->setParameter1( param1 );
653 pAction->setValue( param2 );
655
656 // Null song handling done in MidiActionManager.
657 pActionManager->handleAction( pAction );
658}
659
661{
662 INFOLOG( "processing message" );
663 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_NEXT_PATTERN");
664 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
666
667 // Null song handling done in MidiActionManager.
668 pActionManager->handleAction( pAction );
669}
670
672{
673 INFOLOG( "processing message" );
674 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_ONLY_NEXT_PATTERN");
675 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
677
678 // Null song handling done in MidiActionManager.
679 pActionManager->handleAction( pAction );
680}
681
683{
684 INFOLOG( "processing message" );
685 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_AND_PLAY_PATTERN");
686 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
688
689 // Null song handling done in MidiActionManager.
690 pActionManager->handleAction( pAction );
691}
692
693void OscServer::FILTER_CUTOFF_LEVEL_ABSOLUTE_Handler(QString param1, QString param2)
694{
695 INFOLOG( "processing message" );
696 std::shared_ptr<Action> pAction = std::make_shared<Action>("FILTER_CUTOFF_LEVEL_ABSOLUTE");
697 pAction->setParameter1( param1 );
698 pAction->setValue( param2 );
700
701 // Null song handling done in MidiActionManager.
702 pActionManager->handleAction( pAction );
703}
704
705
706void OscServer::INSTRUMENT_PITCH_Handler( lo_arg** argv, int )
707{
708 INFOLOG( "processing message" );
709
711 setInstrumentPitch( static_cast<int>( argv[0]->f ), argv[1]->f );
712}
713
714void OscServer::BEATCOUNTER_Handler(lo_arg **argv,int i)
715{
716 INFOLOG( "processing message" );
717 std::shared_ptr<Action> pAction = std::make_shared<Action>("BEATCOUNTER");
719
720 // Null song handling done in MidiActionManager.
721 pActionManager->handleAction( pAction );
722}
723
724void OscServer::TAP_TEMPO_Handler(lo_arg **argv,int i)
725{
726 INFOLOG( "processing message" );
727 std::shared_ptr<Action> pAction = std::make_shared<Action>("TAP_TEMPO");
729
730 // Null song handling done in MidiActionManager.
731 pActionManager->handleAction( pAction );
732}
733
734void OscServer::PLAYLIST_SONG_Handler(lo_arg **argv,int i)
735{
736 INFOLOG( "processing message" );
737 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_SONG");
738 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
739
741
742 // Null song handling done in MidiActionManager.
743 pActionManager->handleAction( pAction );
744}
745
747{
748 INFOLOG( "processing message" );
749 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_NEXT_SONG");
751
752 // Null song handling done in MidiActionManager.
753 pActionManager->handleAction( pAction );
754}
755
757{
758 INFOLOG( "processing message" );
759 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_PREV_SONG");
761
762 // Null song handling done in MidiActionManager.
763 pActionManager->handleAction( pAction );
764}
765
766void OscServer::TOGGLE_METRONOME_Handler(lo_arg **argv,int i)
767{
768 INFOLOG( "processing message" );
769 std::shared_ptr<Action> pAction = std::make_shared<Action>("TOGGLE_METRONOME");
771
772 // Null song handling done in MidiActionManager.
773 pActionManager->handleAction( pAction );
774}
775
777{
778 INFOLOG( "processing message" );
779 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_INSTRUMENT");
780 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ) );
781
783
784 // Null song handling done in MidiActionManager.
785 pActionManager->handleAction( pAction );
786}
787
788void OscServer::UNDO_ACTION_Handler(lo_arg **argv,int i)
789{
790 INFOLOG( "processing message" );
791 std::shared_ptr<Action> pAction = std::make_shared<Action>("UNDO_ACTION");
793
794 // This one does also work the current song being nullptr.
795 pActionManager->handleAction( pAction );
796}
797
798void OscServer::REDO_ACTION_Handler(lo_arg **argv,int i)
799{
800 INFOLOG( "processing message" );
801 std::shared_ptr<Action> pAction = std::make_shared<Action>("REDO_ACTION");
803
804 // This one does also work the current song being nullptr.
805 pActionManager->handleAction( pAction );
806}
807
808// -------------------------------------------------------------------
809// Actions required for session management.
810
811void OscServer::NEW_SONG_Handler(lo_arg **argv, int argc) {
812 INFOLOG( "processing message" );
813 auto pHydrogen = H2Core::Hydrogen::get_instance();
814 auto pController = pHydrogen->getCoreActionController();
815 pController->newSong( QString::fromUtf8( &argv[0]->s ) );
816}
817
818void OscServer::OPEN_SONG_Handler(lo_arg **argv, int argc) {
819 INFOLOG( "processing message" );
820 auto pHydrogen = H2Core::Hydrogen::get_instance();
821 auto pController = pHydrogen->getCoreActionController();
822 pController->openSong( QString::fromUtf8( &argv[0]->s ) );
823}
824
825void OscServer::SAVE_SONG_Handler(lo_arg **argv, int argc) {
826 INFOLOG( "processing message" );
827 auto pHydrogen = H2Core::Hydrogen::get_instance();
828 if ( pHydrogen->getSong() == nullptr ) {
829 ERRORLOG( "No song set yet" );
830 return;
831 }
832
833 auto pController = pHydrogen->getCoreActionController();
834 pController->saveSong();
835}
836
837void OscServer::SAVE_SONG_AS_Handler(lo_arg **argv, int argc) {
838 INFOLOG( "processing message" );
839 auto pHydrogen = H2Core::Hydrogen::get_instance();
840 if ( pHydrogen->getSong() == nullptr ) {
841 ERRORLOG( "No song set yet" );
842 return;
843 }
844
845 auto pController = pHydrogen->getCoreActionController();
846 pController->saveSongAs( QString::fromUtf8( &argv[0]->s ) );
847}
848
849void OscServer::SAVE_PREFERENCES_Handler(lo_arg **argv, int argc) {
850 INFOLOG( "processing message" );
851 auto pHydrogen = H2Core::Hydrogen::get_instance();
852 if ( pHydrogen->getSong() == nullptr ) {
853 ERRORLOG( "No song set yet" );
854 return;
855 }
856
857 auto pController = pHydrogen->getCoreActionController();
858 pController->savePreferences();
859}
860
861void OscServer::QUIT_Handler(lo_arg **argv, int argc) {
862 INFOLOG( "processing message" );
863 auto pHydrogen = H2Core::Hydrogen::get_instance();
864 auto pController = pHydrogen->getCoreActionController();
865 pController->quit();
866}
867
868// -------------------------------------------------------------------
869
870void OscServer::TIMELINE_ACTIVATION_Handler(lo_arg **argv, int argc) {
871 INFOLOG( "processing message" );
872 auto pHydrogen = H2Core::Hydrogen::get_instance();
873 if ( pHydrogen->getSong() == nullptr ) {
874 ERRORLOG( "No song set yet" );
875 return;
876 }
877
878 auto pController = pHydrogen->getCoreActionController();
879
880 if ( argv[0]->f != 0 ) {
881 pController->activateTimeline( true );
882 } else {
883 pController->activateTimeline( false );
884 }
885}
886
887void OscServer::TIMELINE_ADD_MARKER_Handler(lo_arg **argv, int argc) {
888 INFOLOG( "processing message" );
889 auto pHydrogen = H2Core::Hydrogen::get_instance();
890 if ( pHydrogen->getSong() == nullptr ) {
891 ERRORLOG( "No song set yet" );
892 return;
893 }
894
895 auto pController = pHydrogen->getCoreActionController();
896 pController->addTempoMarker( static_cast<int>(std::round( argv[0]->f )),
897 argv[1]->f);
898}
899
900void OscServer::TIMELINE_DELETE_MARKER_Handler(lo_arg **argv, int argc) {
901 INFOLOG( "processing message" );
902 auto pHydrogen = H2Core::Hydrogen::get_instance();
903 if ( pHydrogen->getSong() == nullptr ) {
904 ERRORLOG( "No song set yet" );
905 return;
906 }
907
908 auto pController = pHydrogen->getCoreActionController();
909 pController->deleteTempoMarker( static_cast<int>( std::round( argv[0]->f ) ) );
910}
911
912void OscServer::JACK_TRANSPORT_ACTIVATION_Handler(lo_arg **argv, int argc) {
913 INFOLOG( "processing message" );
914 auto pHydrogen = H2Core::Hydrogen::get_instance();
915 if ( pHydrogen->getSong() == nullptr ) {
916 ERRORLOG( "No song set yet" );
917 return;
918 }
919
920 auto pController = pHydrogen->getCoreActionController();
921
922 if ( argv[0]->f != 0 ) {
923 pController->activateJackTransport( true );
924 } else {
925 pController->activateJackTransport( false );
926 }
927}
928
930 INFOLOG( "processing message" );
931 auto pHydrogen = H2Core::Hydrogen::get_instance();
932 if ( pHydrogen->getSong() == nullptr ) {
933 ERRORLOG( "No song set yet" );
934 return;
935 }
936
937 auto pController = pHydrogen->getCoreActionController();
938 if ( argv[0]->f != 0 ) {
939 pController->activateJackTimebaseControl( true );
940 } else {
941 pController->activateJackTimebaseControl( false );
942 }
943}
944
945void OscServer::SONG_MODE_ACTIVATION_Handler(lo_arg **argv, int argc) {
946 INFOLOG( "processing message" );
947 auto pHydrogen = H2Core::Hydrogen::get_instance();
948 if ( pHydrogen->getSong() == nullptr ) {
949 ERRORLOG( "No song set yet" );
950 return;
951 }
952
953 auto pController = pHydrogen->getCoreActionController();
954 if ( argv[0]->f != 0 ) {
955 pController->activateSongMode( true );
956 } else {
957 pController->activateSongMode( false );
958 }
959}
960
961void OscServer::LOOP_MODE_ACTIVATION_Handler(lo_arg **argv, int argc) {
962 INFOLOG( "processing message" );
963 auto pHydrogen = H2Core::Hydrogen::get_instance();
964 if ( pHydrogen->getSong() == nullptr ) {
965 ERRORLOG( "No song set yet" );
966 return;
967 }
968
969 auto pController = pHydrogen->getCoreActionController();
970 if ( argv[0]->f != 0 ) {
971 pController->activateLoopMode( true );
972 } else {
973 pController->activateLoopMode( false );
974 }
975}
976
977void OscServer::RELOCATE_Handler(lo_arg **argv, int argc) {
978 INFOLOG( "processing message" );
979 auto pHydrogen = H2Core::Hydrogen::get_instance();
980 if ( pHydrogen->getSong() == nullptr ) {
981 ERRORLOG( "No song set yet" );
982 return;
983 }
984
985 pHydrogen->getCoreActionController()->locateToColumn( static_cast<int>(std::round( argv[0]->f ) ) );
986}
987
988void OscServer::NEW_PATTERN_Handler(lo_arg **argv, int argc) {
989 INFOLOG( "processing message" );
990 auto pHydrogen = H2Core::Hydrogen::get_instance();
991 if ( pHydrogen->getSong() == nullptr ) {
992 ERRORLOG( "No song set yet" );
993 return;
994 }
995
996 auto pController = pHydrogen->getCoreActionController();
997 pController->newPattern( QString::fromUtf8( &argv[0]->s ) );
998}
999
1000void OscServer::OPEN_PATTERN_Handler(lo_arg **argv, int argc) {
1001 INFOLOG( "processing message" );
1002 auto pHydrogen = H2Core::Hydrogen::get_instance();
1003 if ( pHydrogen->getSong() == nullptr ) {
1004 ERRORLOG( "No song set yet" );
1005 return;
1006 }
1007
1008 auto pController = pHydrogen->getCoreActionController();
1009 pController->openPattern( QString::fromUtf8( &argv[0]->s ) );
1010}
1011
1012void OscServer::REMOVE_PATTERN_Handler(lo_arg **argv, int argc) {
1013 INFOLOG( "processing message" );
1014 auto pHydrogen = H2Core::Hydrogen::get_instance();
1015 if ( pHydrogen->getSong() == nullptr ) {
1016 ERRORLOG( "No song set yet" );
1017 return;
1018 }
1019
1020 auto pController = pHydrogen->getCoreActionController();
1021 pController->removePattern( static_cast<int>(std::round( argv[0]->f )) );
1022}
1023
1025{
1026 INFOLOG( "processing message" );
1027 auto pHydrogen = H2Core::Hydrogen::get_instance();
1028 const int nInstr = pHydrogen->getSelectedInstrumentNumber();
1029 if ( nInstr == -1 ) {
1030 WARNINGLOG( "No instrument selected" );
1031 return;
1032 }
1033
1034 pHydrogen->getCoreActionController()->clearInstrumentInPattern( nInstr );
1035}
1036
1038{
1039 INFOLOG( "processing message" );
1041 ->clearInstrumentInPattern( static_cast<int>(std::round( argv[0]->f )) );
1042}
1043
1044void OscServer::CLEAR_PATTERN_Handler( lo_arg **argv, int i )
1045{
1046 INFOLOG( "processing message" );
1047 std::shared_ptr<Action> pAction = std::make_shared<Action>( "CLEAR_PATTERN" );
1049}
1050
1051void OscServer::NOTE_ON_Handler( lo_arg **argv, int i )
1052{
1053 const int nNote = static_cast<int>( std::round( argv[0]->f ) );
1054 if ( nNote < H2Core::MidiMessage::instrumentOffset || nNote > 127 ) {
1055 ERRORLOG( QString( "Provided note [%1] out of bound [%2,127]." )
1056 .arg( nNote ).arg( H2Core::MidiMessage::instrumentOffset ) );
1057 return;
1058 }
1059
1060 float fVelocity = argv[1]->f;
1061 if ( fVelocity < 0 ) {
1062 WARNINGLOG( QString( "Provided velocity [%1] out of bound. Using minimum value [0] instead." )
1063 .arg( fVelocity ) );
1064 fVelocity = 0;
1065 }
1066 else if ( fVelocity > 1.0 ) {
1067 WARNINGLOG( QString( "Provided velocity [%1] out of bound. Using maximum value [1.0] instead." )
1068 .arg( fVelocity ) );
1069 fVelocity = 1.0;
1070 }
1071
1072 INFOLOG( QString( "processing message with note: [%1] and velocity: [%2]" )
1073 .arg( nNote ).arg( fVelocity ) );
1074
1076 ->handleNote( nNote, fVelocity, false );
1077}
1078
1079void OscServer::NOTE_OFF_Handler( lo_arg** argv, int i )
1080{
1081 const int nNote = static_cast<int>( std::round( argv[0]->f ) );
1082 if ( nNote < H2Core::MidiMessage::instrumentOffset || nNote > 127 ) {
1083 ERRORLOG( QString( "Provided note [%1] out of bound [%2,127]." )
1084 .arg( nNote ).arg( H2Core::MidiMessage::instrumentOffset ) );
1085 return;
1086 }
1087
1088 INFOLOG( QString( "processing message with note: [%1]" ).arg( nNote ) );
1089
1091 ->handleNote( nNote, 0.0, true );
1092}
1093
1095 INFOLOG( "processing message" );
1096 auto pHydrogen = H2Core::Hydrogen::get_instance();
1097 if ( pHydrogen->getSong() == nullptr ) {
1098 ERRORLOG( "No song set yet" );
1099 return;
1100 }
1101
1102 auto pController = pHydrogen->getCoreActionController();
1103 pController->toggleGridCell( static_cast<int>(std::round( argv[0]->f )),
1104 static_cast<int>(std::round( argv[1]->f )) );
1105}
1106
1107void OscServer::LOAD_DRUMKIT_Handler(lo_arg **argv, int argc) {
1108 INFOLOG( "processing message" );
1109 auto pHydrogen = H2Core::Hydrogen::get_instance();
1110 if ( pHydrogen->getSong() == nullptr ) {
1111 ERRORLOG( "No song set yet" );
1112 return;
1113 }
1114
1115 auto pController = pHydrogen->getCoreActionController();
1116
1117 bool bConditionalLoad = true;
1118 if ( argc > 1 ) {
1119 bConditionalLoad = argv[1]->f == 0 ? false : true;
1120 }
1121
1122 pController->setDrumkit( QString::fromUtf8( &argv[0]->s ),
1123 bConditionalLoad );
1124}
1125
1126void OscServer::UPGRADE_DRUMKIT_Handler(lo_arg **argv, int argc) {
1127 INFOLOG( "processing message" );
1128
1130
1131 QString sNewPath = "";
1132 if ( argc > 1 ) {
1133 sNewPath = QString::fromUtf8( &argv[1]->s );
1134 }
1135
1136 pController->upgradeDrumkit( QString::fromUtf8( &argv[0]->s ),
1137 sNewPath );
1138}
1139
1140void OscServer::VALIDATE_DRUMKIT_Handler(lo_arg **argv, int argc) {
1141 INFOLOG( "processing message" );
1142
1143 bool bValidateLegacyKits = false;
1144 if ( argc > 1 ) {
1145 bValidateLegacyKits = argv[1]->f == 0 ? false : true;
1146 }
1147
1149 pController->validateDrumkit( QString::fromUtf8( &argv[0]->s ),
1150 bValidateLegacyKits );
1151}
1152
1153void OscServer::EXTRACT_DRUMKIT_Handler(lo_arg **argv, int argc) {
1154 INFOLOG( "processing message" );
1155
1157
1158 QString sTargetDir = "";
1159 if ( argc > 1 ) {
1160 sTargetDir = QString::fromUtf8( &argv[1]->s );
1161 }
1162
1163 pController->extractDrumkit( QString::fromUtf8( &argv[0]->s ), sTargetDir );
1164}
1165
1166// -------------------------------------------------------------------
1167// Helper functions
1168
1169bool IsLoAddressEqual( lo_address first, lo_address second )
1170{
1171 bool portEqual = ( strcmp( lo_address_get_port( first ), lo_address_get_port( second ) ) == 0);
1172 bool hostEqual = ( strcmp( lo_address_get_hostname( first ), lo_address_get_hostname( second ) ) == 0);
1173 bool protoEqual = ( lo_address_get_protocol( first ) == lo_address_get_protocol( second ) );
1174
1175 return portEqual && hostEqual && protoEqual;
1176}
1177
1178void OscServer::broadcastMessage( const char* msgText, lo_message message ) {
1179 for ( const auto& clientAddress: m_pClientRegistry ){
1180
1181 INFOLOG( QString( "Outgoing OSC broadcast message %1" ).arg( msgText ));
1182
1183 int i;
1184 for (i = 0; i < lo_message_get_argc( message ); i++) {
1185 QString formattedArgument = qPrettyPrint( (lo_type)lo_message_get_types(message)[i], lo_message_get_argv(message)[i] );
1186 INFOLOG(QString("Argument %1: %2 %3").arg(i).arg(lo_message_get_types(message)[i]).arg(formattedArgument));
1187 }
1188
1189 lo_send_message(clientAddress, msgText, message);
1190 }
1191}
1192
1193// -------------------------------------------------------------------
1194// Main action handler
1195
1196void OscServer::handleAction( std::shared_ptr<Action> pAction )
1197{
1199
1200 if( !pPref->getOscFeedbackEnabled() ){
1201 return;
1202 }
1203
1204 if( pAction->getType() == "MASTER_VOLUME_ABSOLUTE"){
1205 bool ok;
1206 float fValue = pAction->getValue().toFloat(&ok);
1207
1208 lo_message reply = lo_message_new();
1209 lo_message_add_float( reply, fValue );
1210
1211 broadcastMessage("/Hydrogen/MASTER_VOLUME_ABSOLUTE", reply);
1212
1213 lo_message_free( reply );
1214 }
1215
1216 if( pAction->getType() == "STRIP_VOLUME_ABSOLUTE"){
1217 bool ok;
1218 float fValue = pAction->getValue().toFloat(&ok);
1219
1220 lo_message reply = lo_message_new();
1221 lo_message_add_float( reply, fValue );
1222
1223 QByteArray ba = QString("/Hydrogen/STRIP_VOLUME_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1224 const char *c_str2 = ba.data();
1225
1226 broadcastMessage( c_str2, reply);
1227
1228 lo_message_free( reply );
1229 }
1230
1231 if( pAction->getType() == "TOGGLE_METRONOME"){
1232 bool ok;
1233 float param1 = pAction->getParameter1().toFloat(&ok);
1234
1235 lo_message reply = lo_message_new();
1236 lo_message_add_float(reply, param1);
1237
1238 broadcastMessage("/Hydrogen/TOGGLE_METRONOME", reply);
1239
1240 lo_message_free( reply );
1241 }
1242
1243 if( pAction->getType() == "MUTE_TOGGLE"){
1244 bool ok;
1245 float param1 = pAction->getParameter1().toFloat(&ok);
1246
1247 lo_message reply = lo_message_new();
1248 lo_message_add_float(reply, param1);
1249
1250 broadcastMessage("/Hydrogen/MUTE_TOGGLE", reply);
1251
1252 lo_message_free( reply );
1253 }
1254
1255 if( pAction->getType() == "STRIP_MUTE_TOGGLE"){
1256 bool ok;
1257 float fValue = pAction->getValue().toFloat(&ok);
1258
1259 lo_message reply = lo_message_new();
1260 lo_message_add_float( reply, fValue );
1261
1262 QByteArray ba = QString("/Hydrogen/STRIP_MUTE_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1263 const char *c_str2 = ba.data();
1264
1265 broadcastMessage( c_str2, reply);
1266
1267 lo_message_free( reply );
1268 }
1269
1270 if( pAction->getType() == "STRIP_SOLO_TOGGLE"){
1271 bool ok;
1272 float fValue = pAction->getValue().toFloat(&ok);
1273
1274 lo_message reply = lo_message_new();
1275 lo_message_add_float( reply, fValue );
1276
1277 QByteArray ba = QString("/Hydrogen/STRIP_SOLO_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1278 const char *c_str2 = ba.data();
1279
1280 broadcastMessage( c_str2, reply);
1281
1282 lo_message_free( reply );
1283 }
1284
1285 if( pAction->getType() == "PAN_ABSOLUTE"){
1286 bool ok;
1287 float fValue = pAction->getValue().toFloat(&ok);
1288
1289 lo_message reply = lo_message_new();
1290 lo_message_add_float( reply, fValue );
1291
1292 QByteArray ba = QString("/Hydrogen/PAN_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1293 const char *c_str2 = ba.data();
1294
1295 broadcastMessage( c_str2, reply);
1296
1297 lo_message_free( reply );
1298 }
1299
1300 if( pAction->getType() == "PAN_ABSOLUTE_SYM"){
1301 bool ok;
1302 float fValue = pAction->getValue().toFloat(&ok);
1303
1304 lo_message reply = lo_message_new();
1305 lo_message_add_float( reply, fValue );
1306
1307 QByteArray ba = QString("/Hydrogen/PAN_ABSOLUTE_SYM/%1").arg(pAction->getParameter1()).toLatin1();
1308 const char *c_str2 = ba.data();
1309
1310 broadcastMessage( c_str2, reply);
1311
1312 lo_message_free( reply );
1313 }
1314}
1315
1317{
1318 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1319 ERRORLOG("Failed to initialize OSC server. No valid server thread.");
1320 return false;
1321 }
1322
1323 /*
1324 * Register all handler functions
1325 */
1326
1327 //This handler is responsible for registering clients
1328 m_pServerThread->add_method(nullptr, nullptr, [&](lo_message msg){
1329 lo_address address = lo_message_get_source(msg);
1330
1331 bool AddressRegistered = false;
1332 for ( const auto& cclientAddress : m_pClientRegistry ){
1333 if ( IsLoAddressEqual( address, cclientAddress ) ) {
1334 AddressRegistered = true;
1335 break;
1336 }
1337 }
1338
1339 if( ! AddressRegistered ){
1340 lo_address newAddress =
1341 lo_address_new_with_proto( lo_address_get_protocol( address ),
1342 lo_address_get_hostname( address ),
1343 lo_address_get_port( address ) );
1344 m_pClientRegistry.push_back( newAddress );
1345 INFOLOG( QString( "New OSC client registered. Hostname: %1, port: %2, protocol: %3" )
1346 .arg( lo_address_get_hostname( address ) )
1347 .arg( lo_address_get_port( address ) )
1348 .arg( lo_address_get_protocol( address ) ) );
1349
1352 }
1353
1354 // Returning 1 means that the
1355 // message has not been fully
1356 // handled and the server should
1357 // try other methods.
1358 return 1;
1359 });
1360
1361 m_pServerThread->add_method(nullptr, nullptr, incomingMessageLogging, nullptr);
1362
1363 m_pServerThread->add_method("/Hydrogen/PLAY", "", PLAY_Handler);
1364 m_pServerThread->add_method("/Hydrogen/PLAY", "f", PLAY_Handler);
1365 m_pServerThread->add_method("/Hydrogen/PLAY_STOP_TOGGLE", "", PLAY_STOP_TOGGLE_Handler);
1366 m_pServerThread->add_method("/Hydrogen/PLAY_STOP_TOGGLE", "f", PLAY_STOP_TOGGLE_Handler);
1367 m_pServerThread->add_method("/Hydrogen/PLAY_PAUSE_TOGGLE", "", PLAY_PAUSE_TOGGLE_Handler);
1368 m_pServerThread->add_method("/Hydrogen/PLAY_PAUSE_TOGGLE", "f", PLAY_PAUSE_TOGGLE_Handler);
1369 m_pServerThread->add_method("/Hydrogen/STOP", "", STOP_Handler);
1370 m_pServerThread->add_method("/Hydrogen/STOP", "f", STOP_Handler);
1371 m_pServerThread->add_method("/Hydrogen/PAUSE", "", PAUSE_Handler);
1372 m_pServerThread->add_method("/Hydrogen/PAUSE", "f", PAUSE_Handler);
1373
1374 m_pServerThread->add_method("/Hydrogen/RECORD_READY", "", RECORD_READY_Handler);
1375 m_pServerThread->add_method("/Hydrogen/RECORD_READY", "f", RECORD_READY_Handler);
1376 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE_TOGGLE", "", RECORD_STROBE_TOGGLE_Handler);
1377 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE_TOGGLE", "f", RECORD_STROBE_TOGGLE_Handler);
1378 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE", "", RECORD_STROBE_Handler);
1379 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE", "f", RECORD_STROBE_Handler);
1380 m_pServerThread->add_method("/Hydrogen/RECORD_EXIT", "", RECORD_EXIT_Handler);
1381 m_pServerThread->add_method("/Hydrogen/RECORD_EXIT", "f", RECORD_EXIT_Handler);
1382
1383 m_pServerThread->add_method("/Hydrogen/MUTE", "", MUTE_Handler);
1384 m_pServerThread->add_method("/Hydrogen/MUTE", "f", MUTE_Handler);
1385 m_pServerThread->add_method("/Hydrogen/UNMUTE", "", UNMUTE_Handler);
1386 m_pServerThread->add_method("/Hydrogen/UNMUTE", "f", UNMUTE_Handler);
1387 m_pServerThread->add_method("/Hydrogen/MUTE_TOGGLE", "", MUTE_TOGGLE_Handler);
1388 m_pServerThread->add_method("/Hydrogen/MUTE_TOGGLE", "f", MUTE_TOGGLE_Handler);
1389
1390 m_pServerThread->add_method("/Hydrogen/INSTRUMENT_PITCH", "ff",
1392
1393 m_pServerThread->add_method("/Hydrogen/NEXT_BAR", "", NEXT_BAR_Handler);
1394 m_pServerThread->add_method("/Hydrogen/NEXT_BAR", "f", NEXT_BAR_Handler);
1395 m_pServerThread->add_method("/Hydrogen/PREVIOUS_BAR", "", PREVIOUS_BAR_Handler);
1396 m_pServerThread->add_method("/Hydrogen/PREVIOUS_BAR", "f", PREVIOUS_BAR_Handler);
1397
1398 m_pServerThread->add_method("/Hydrogen/BPM", "f", BPM_Handler);
1399 m_pServerThread->add_method("/Hydrogen/BPM_DECR", "f", BPM_DECR_Handler);
1400 m_pServerThread->add_method("/Hydrogen/BPM_INCR", "f", BPM_INCR_Handler);
1401
1402 m_pServerThread->add_method("/Hydrogen/MASTER_VOLUME_ABSOLUTE", "f", MASTER_VOLUME_ABSOLUTE_Handler);
1403 m_pServerThread->add_method("/Hydrogen/MASTER_VOLUME_RELATIVE", "f", MASTER_VOLUME_RELATIVE_Handler);
1404
1405 m_pServerThread->add_method("/Hydrogen/SELECT_NEXT_PATTERN", "f", SELECT_NEXT_PATTERN_Handler);
1406 m_pServerThread->add_method("/Hydrogen/SELECT_ONLY_NEXT_PATTERN", "f", SELECT_ONLY_NEXT_PATTERN_Handler);
1407 m_pServerThread->add_method("/Hydrogen/SELECT_AND_PLAY_PATTERN", "f", SELECT_AND_PLAY_PATTERN_Handler);
1408
1409 m_pServerThread->add_method("/Hydrogen/BEATCOUNTER", "", BEATCOUNTER_Handler);
1410 m_pServerThread->add_method("/Hydrogen/BEATCOUNTER", "f", BEATCOUNTER_Handler);
1411
1412 m_pServerThread->add_method("/Hydrogen/TAP_TEMPO", "", TAP_TEMPO_Handler);
1413 m_pServerThread->add_method("/Hydrogen/TAP_TEMPO", "f", TAP_TEMPO_Handler);
1414
1415 m_pServerThread->add_method("/Hydrogen/PLAYLIST_SONG", "f", PLAYLIST_SONG_Handler);
1416 m_pServerThread->add_method("/Hydrogen/PLAYLIST_NEXT_SONG", "", PLAYLIST_NEXT_SONG_Handler);
1417 m_pServerThread->add_method("/Hydrogen/PLAYLIST_NEXT_SONG", "f", PLAYLIST_NEXT_SONG_Handler);
1418 m_pServerThread->add_method("/Hydrogen/PLAYLIST_PREV_SONG", "", PLAYLIST_PREV_SONG_Handler);
1419 m_pServerThread->add_method("/Hydrogen/PLAYLIST_PREV_SONG", "f", PLAYLIST_PREV_SONG_Handler);
1420
1421 m_pServerThread->add_method("/Hydrogen/TOGGLE_METRONOME", "", TOGGLE_METRONOME_Handler);
1422 m_pServerThread->add_method("/Hydrogen/TOGGLE_METRONOME", "f", TOGGLE_METRONOME_Handler);
1423
1424 m_pServerThread->add_method("/Hydrogen/SELECT_INSTRUMENT", "f", SELECT_INSTRUMENT_Handler);
1425
1426 m_pServerThread->add_method("/Hydrogen/UNDO_ACTION", "", UNDO_ACTION_Handler);
1427 m_pServerThread->add_method("/Hydrogen/UNDO_ACTION", "f", UNDO_ACTION_Handler);
1428 m_pServerThread->add_method("/Hydrogen/REDO_ACTION", "", REDO_ACTION_Handler);
1429 m_pServerThread->add_method("/Hydrogen/REDO_ACTION", "f", REDO_ACTION_Handler);
1430
1431 m_pServerThread->add_method("/Hydrogen/NEW_SONG", "s", NEW_SONG_Handler);
1432 m_pServerThread->add_method("/Hydrogen/OPEN_SONG", "s", OPEN_SONG_Handler);
1433 m_pServerThread->add_method("/Hydrogen/SAVE_SONG", "", SAVE_SONG_Handler);
1434 m_pServerThread->add_method("/Hydrogen/SAVE_SONG", "f", SAVE_SONG_Handler);
1435 m_pServerThread->add_method("/Hydrogen/SAVE_SONG_AS", "s", SAVE_SONG_AS_Handler);
1436 m_pServerThread->add_method("/Hydrogen/SAVE_PREFERENCES", "", SAVE_SONG_Handler);
1437 m_pServerThread->add_method("/Hydrogen/SAVE_PREFERENCES", "f", SAVE_SONG_Handler);
1438 m_pServerThread->add_method("/Hydrogen/QUIT", "", QUIT_Handler);
1439 m_pServerThread->add_method("/Hydrogen/QUIT", "f", QUIT_Handler);
1440
1441 m_pServerThread->add_method("/Hydrogen/TIMELINE_ACTIVATION", "f", TIMELINE_ACTIVATION_Handler);
1442 m_pServerThread->add_method("/Hydrogen/TIMELINE_ADD_MARKER", "ff", TIMELINE_ADD_MARKER_Handler);
1443 m_pServerThread->add_method("/Hydrogen/TIMELINE_DELETE_MARKER", "f", TIMELINE_DELETE_MARKER_Handler);
1444
1445 m_pServerThread->add_method("/Hydrogen/JACK_TRANSPORT_ACTIVATION", "f", JACK_TRANSPORT_ACTIVATION_Handler);
1446 m_pServerThread->add_method("/Hydrogen/JACK_TIMEBASE_MASTER_ACTIVATION", "f", JACK_TIMEBASE_MASTER_ACTIVATION_Handler);
1447 m_pServerThread->add_method("/Hydrogen/SONG_MODE_ACTIVATION", "f", SONG_MODE_ACTIVATION_Handler);
1448 m_pServerThread->add_method("/Hydrogen/LOOP_MODE_ACTIVATION", "f", LOOP_MODE_ACTIVATION_Handler);
1449 m_pServerThread->add_method("/Hydrogen/RELOCATE", "f", RELOCATE_Handler);
1450 m_pServerThread->add_method("/Hydrogen/NEW_PATTERN", "s", NEW_PATTERN_Handler);
1451 m_pServerThread->add_method("/Hydrogen/OPEN_PATTERN", "s", OPEN_PATTERN_Handler);
1452 m_pServerThread->add_method("/Hydrogen/REMOVE_PATTERN", "f", REMOVE_PATTERN_Handler);
1453 m_pServerThread->add_method("/Hydrogen/CLEAR_INSTRUMENT", "f", CLEAR_INSTRUMENT_Handler);
1454 m_pServerThread->add_method("/Hydrogen/CLEAR_SELECTED_INSTRUMENT", "",
1456 m_pServerThread->add_method("/Hydrogen/CLEAR_SELECTED_INSTRUMENT", "f",
1458 m_pServerThread->add_method("/Hydrogen/CLEAR_PATTERN", "", CLEAR_PATTERN_Handler);
1459 m_pServerThread->add_method("/Hydrogen/CLEAR_PATTERN", "f", CLEAR_PATTERN_Handler);
1460
1461 m_pServerThread->add_method("/Hydrogen/NOTE_ON", "ff", NOTE_ON_Handler);
1462 m_pServerThread->add_method("/Hydrogen/NOTE_OFF", "f", NOTE_OFF_Handler);
1463
1464 m_pServerThread->add_method("/Hydrogen/SONG_EDITOR_TOGGLE_GRID_CELL", "ff", SONG_EDITOR_TOGGLE_GRID_CELL_Handler);
1465 m_pServerThread->add_method("/Hydrogen/LOAD_DRUMKIT", "s", LOAD_DRUMKIT_Handler);
1466 m_pServerThread->add_method("/Hydrogen/LOAD_DRUMKIT", "sf", LOAD_DRUMKIT_Handler);
1467 m_pServerThread->add_method("/Hydrogen/UPGRADE_DRUMKIT", "s", UPGRADE_DRUMKIT_Handler);
1468 m_pServerThread->add_method("/Hydrogen/UPGRADE_DRUMKIT", "ss", UPGRADE_DRUMKIT_Handler);
1469 m_pServerThread->add_method("/Hydrogen/VALIDATE_DRUMKIT", "s", VALIDATE_DRUMKIT_Handler);
1470 m_pServerThread->add_method("/Hydrogen/VALIDATE_DRUMKIT", "sf", VALIDATE_DRUMKIT_Handler);
1471 m_pServerThread->add_method("/Hydrogen/EXTRACT_DRUMKIT", "s", EXTRACT_DRUMKIT_Handler);
1472 m_pServerThread->add_method("/Hydrogen/EXTRACT_DRUMKIT", "ss", EXTRACT_DRUMKIT_Handler);
1473
1474 m_pServerThread->add_method(nullptr, nullptr, generic_handler, nullptr);
1475
1476 m_bInitialized = true;
1477
1478 return true;
1479}
1480
1482 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1483 ERRORLOG("Failed to start OSC server. No valid server thread.");
1484 return false;
1485 }
1486
1487 if ( ! m_bInitialized ) {
1488 if ( ! init() ) {
1489 return false;
1490 }
1491 }
1492
1493 m_pServerThread->start();
1494
1495 int nOscPortUsed;
1496 if ( m_pPreferences->m_nOscTemporaryPort != -1 ) {
1497 nOscPortUsed = m_pPreferences->m_nOscTemporaryPort;
1498 } else {
1499 nOscPortUsed = m_pPreferences->getOscServerPort();
1500 }
1501
1502 INFOLOG( QString( "Osc server started. Listening on port %1" )
1503 .arg( nOscPortUsed ) );
1504
1505 return true;
1506}
1507
1509 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1510 ERRORLOG("Failed to stop OSC server. No valid server thread.");
1511 return false;
1512 }
1513
1514 m_pServerThread->stop();
1515 INFOLOG(QString("Osc server stopped" ));
1516
1517 return true;
1518}
1519
1520#endif /* H2CORE_HAVE_OSC */
1521
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:61
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
bool IsLoAddressEqual(lo_address first, lo_address second)
bool clearInstrumentInPattern(int nInstrumentNumber, int nPatternNumber=-1)
Deletes all notes for instrument pInstrument in a specified pattern.
bool handleNote(int nNote, float fVelocity, bool bNoteOff=false)
Handle an incoming note event, e.g.
bool extractDrumkit(const QString &sDrumkitPath, const QString &sTargetDir="", QString *pInstalledPath=nullptr, bool *pEncodingIssuesDetected=nullptr)
Extracts the compressed .h2drumkit file in sDrumkitPath into sTargetDir.
bool setStripVolume(int nStrip, float fVolumeValue, bool bSelectStrip)
bool validateDrumkit(const QString &sDrumkitPath, bool bCheckLegacyVersions=false)
Checks whether the provided drumkit in sDrumkitPath can be found, can be loaded, and does comply with...
bool upgradeDrumkit(const QString &sDrumkitPath, const QString &sNewPath="")
Upgrades the drumkit found at absolute path sDrumkitPath.
bool setMasterVolume(float masterVolumeValue)
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
Hydrogen Audio Engine.
Definition Hydrogen.h:54
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:653
static constexpr int instrumentOffset
When recording notes using MIDI NOTE_ON events this offset will be applied to the provided pitch in o...
Definition MidiCommon.h:91
Manager for User Preferences File (singleton)
Definition Preferences.h:79
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
The MidiActionManager cares for the execution of MidiActions.
Definition MidiAction.h:142
bool handleAction(std::shared_ptr< Action > action)
The handleAction method is the heart of the MidiActionManager class.
static MidiActionManager * get_instance()
Returns a pointer to the current MidiActionManager singleton stored in __instance.
Definition MidiAction.h:255
OSC Server implementation.
Definition OscServer.h:90
static void UPGRADE_DRUMKIT_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::upgradeDrumkit().
bool m_bInitialized
Used to determine whether the callback methods were already added to m_pServerThread.
Definition OscServer.h:911
static void MUTE_TOGGLE_Handler(lo_arg **argv, int i)
Creates an Action of type MUTE_TOGGLE and passes its references to MidiActionManager::handleAction().
static void RECORD_READY_Handler(lo_arg **argv, int i)
Creates an Action of type RECORD_READY and passes its references to MidiActionManager::handleAction()...
static void EXTRACT_DRUMKIT_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::extractDrumkit().
static void PLAYLIST_PREV_SONG_Handler(lo_arg **argv, int i)
Creates an Action of type PLAYLIST_PREV_SONG and passes its references to MidiActionManager::handleAc...
static void PLAYLIST_SONG_Handler(lo_arg **argv, int i)
Creates an Action of type PLAYLIST_SONG and passes its references to MidiActionManager::handleAction(...
~OscServer()
Destructor freeing all addresses in m_pClientRegistry and setting __instance to nullptr.
static void REMOVE_PATTERN_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::removePattern().
std::list< lo_address > m_pClientRegistry
List of all OSC clients known to Hydrogen.
Definition OscServer.h:930
static void BEATCOUNTER_Handler(lo_arg **argv, int i)
Creates an Action of type BEATCOUNTER and passes its references to MidiActionManager::handleAction().
static void SONG_MODE_ACTIVATION_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::activateSongMode().
static int incomingMessageLogging(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data)
static void INSTRUMENT_PITCH_Handler(lo_arg **argv, int t)
static void LOOP_MODE_ACTIVATION_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::activateLoopMode().
static void TIMELINE_ACTIVATION_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::activateTimeline().
static void PLAY_Handler(lo_arg **argv, int i)
Creates an Action of type PLAY and passes its references to MidiActionManager::handleAction().
H2Core::Preferences * m_pPreferences
Pointer to the H2Core::Preferences singleton.
Definition OscServer.h:906
static void UNDO_ACTION_Handler(lo_arg **argv, int i)
Creates an Action of type UNDO_ACTION and passes its references to MidiActionManager::handleAction().
static void VALIDATE_DRUMKIT_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::validateDrumkit().
static void BPM_Handler(lo_arg **argv, int i)
Creates sets the current tempo of Hydrogen to the provided value (first argument in argv).
static void TIMELINE_DELETE_MARKER_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::deleteTempoMarker().
OscServer(H2Core::Preferences *pPreferences)
Private constructor creating a new OSC server thread using the port H2Core::Preferences::m_nOscServer...
static void MASTER_VOLUME_ABSOLUTE_Handler(lo_arg **argv, int i)
Calls H2Core::CoreActionController::setMasterVolume() with the first argument in argv.
static void RELOCATE_Handler(lo_arg **argv, int argc)
static void JACK_TIMEBASE_MASTER_ACTIVATION_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::activateJackTimebaseControl().
static void REDO_ACTION_Handler(lo_arg **argv, int argc)
Creates an Action of type REDO_ACTION and passes its references to MidiActionManager::handleAction().
static void MUTE_Handler(lo_arg **argv, int i)
Creates an Action of type MUTE and passes its references to MidiActionManager::handleAction().
static void TOGGLE_METRONOME_Handler(lo_arg **argv, int i)
Creates an Action of type TOGGLE_METRONOME and passes its references to MidiActionManager::handleActi...
static void NEW_PATTERN_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::newSong().
static void PLAY_STOP_TOGGLE_Handler(lo_arg **argv, int i)
Creates an Action of type PLAY/STOP_TOGGLE and passes its references to MidiActionManager::handleActi...
static QString qPrettyPrint(lo_type type, void *data)
Converts a data data of type type into a printable QString.
Definition OscServer.cpp:50
bool stop()
Stops the OSC server and makes it unavailable.
static void SELECT_AND_PLAY_PATTERN_Handler(lo_arg **argv, int i)
Creates an Action of type SELECT_AND_PLAY_PATTERN and passes its references to MidiActionManager::han...
static void JACK_TRANSPORT_ACTIVATION_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::activatedJackTransport().
static void SAVE_SONG_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::saveSong().
static void CLEAR_INSTRUMENT_Handler(lo_arg **argv, int argc)
The handler expects the user to provide the number of the instrument for which all notes should be re...
static void SAVE_PREFERENCES_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::savePreferences().
static void LOAD_DRUMKIT_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::setDrumkit().
static void PLAY_PAUSE_TOGGLE_Handler(lo_arg **argv, int i)
Creates an Action of type PLAY/PAUSE_TOGGLE and passes its references to MidiActionManager::handleAct...
static void STRIP_VOLUME_RELATIVE_Handler(QString param1, QString param2)
Creates an Action of type STRIP_VOLUME_RELATIVE and passes its references to MidiActionManager::handl...
lo::ServerThread * m_pServerThread
Object containing the actual thread with an OSC server running in.
Definition OscServer.h:919
static void UNMUTE_Handler(lo_arg **argv, int i)
Creates an Action of type UNMUTE and passes its references to MidiActionManager::handleAction().
static void SELECT_ONLY_NEXT_PATTERN_Handler(lo_arg **argv, int i)
Creates an Action of type SELECT_ONLY_NEXT_PATTERN and passes its references to MidiActionManager::ha...
static void TAP_TEMPO_Handler(lo_arg **argv, int i)
Creates an Action of type TAP_TEMPO and passes its references to MidiActionManager::handleAction().
static void NOTE_ON_Handler(lo_arg **argv, int argc)
Provides a similar behavior as a NOTE_ON MIDI message.
static void OPEN_PATTERN_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::openPattern().
static void SELECT_NEXT_PATTERN_Handler(lo_arg **argv, int i)
Creates an Action of type SELECT_NEXT_PATTERN and passes its references to MidiActionManager::handleA...
static void SELECT_INSTRUMENT_Handler(lo_arg **argv, int i)
Creates an Action of type SELECT_INSTRUMENT and passes its references to MidiActionManager::handleAct...
static void OPEN_SONG_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::openSong().
static void BPM_DECR_Handler(lo_arg **argv, int i)
Creates an Action of type BPM_DECR and passes its references to MidiActionManager::handleAction().
static void CLEAR_SELECTED_INSTRUMENT_Handler(lo_arg **argv, int argc)
static void RECORD_STROBE_TOGGLE_Handler(lo_arg **argv, int i)
Creates an Action of type RECORD/STROBE_TOGGLE and passes its references to MidiActionManager::handle...
static void NEW_SONG_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::newSong().
static void FILTER_CUTOFF_LEVEL_ABSOLUTE_Handler(QString param1, QString param2)
Creates an Action of type FILTER_CUTOFF_LEVEL_ABSOLUTE and passes its references to MidiActionManager...
static void PAUSE_Handler(lo_arg **argv, int i)
Creates an Action of type PAUSE and passes its references to MidiActionManager::handleAction().
static void TIMELINE_ADD_MARKER_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::addTempoMarker().
static void MASTER_VOLUME_RELATIVE_Handler(lo_arg **argv, int i)
Creates an Action of type MASTER_VOLUME_RELATIVE and passes its references to MidiActionManager::hand...
static void STOP_Handler(lo_arg **argv, int i)
Creates an Action of type STOP and passes its references to MidiActionManager::handleAction().
bool start()
Starts the OSC server and makes it available to handle commands.
static void STRIP_VOLUME_ABSOLUTE_Handler(int param1, float param2)
Calls H2Core::CoreActionController::setStripVolume() with both param1 and param2.
static int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data)
Catches any incoming messages and display them.
void handleAction(std::shared_ptr< Action > pAction)
Function called by H2Core::CoreActionController::initExternalControlInterfaces() to inform all client...
static OscServer * __instance
Object holding the current OscServer singleton.
Definition OscServer.h:98
static void QUIT_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::quit().
static void RECORD_EXIT_Handler(lo_arg **argv, int i)
Creates an Action of type EXIT and passes its references to MidiActionManager::handleAction().
static void NEXT_BAR_Handler(lo_arg **argv, int i)
Creates an Action of type >>_NEXT_BAR and passes its references to MidiActionManager::handleAction().
static void CLEAR_PATTERN_Handler(lo_arg **argv, int argc)
The handler removes all notes from the the currently selected pattern.
static void BPM_INCR_Handler(lo_arg **argv, int i)
Creates an Action of type BPM_INCR and passes its references to MidiActionManager::handleAction().
static void SONG_EDITOR_TOGGLE_GRID_CELL_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::songEditorToggleGridCell().
static void create_instance(H2Core::Preferences *pPreferences)
If __instance equals nullptr, a new OscServer singleton will be created by calling the OscServer() co...
static void RECORD_STROBE_Handler(lo_arg **argv, int i)
Creates an Action of type RECORD_STROBE and passes its references to MidiActionManager::handleAction(...
static void PREVIOUS_BAR_Handler(lo_arg **argv, int i)
Creates an Action of type <<_PREVIOUS_BAR and passes its references to MidiActionManager::handleActio...
static void PLAYLIST_NEXT_SONG_Handler(lo_arg **argv, int i)
Creates an Action of type PLAYLIST_NEXT_SONG and passes its references to MidiActionManager::handleAc...
static void NOTE_OFF_Handler(lo_arg **argv, int argc)
Provides a similar behavior as a NOTE_OFF MIDI message.
bool init()
Registers all handler functions.
static void SAVE_SONG_AS_Handler(lo_arg **argv, int argc)
Triggers CoreActionController::saveSongAs().
void broadcastMessage(const char *msgText, lo_message message)
Helper function which sends a message with msgText to all connected clients.
#define MAX_BPM
Definition Globals.h:36
#define MIN_BPM
Definition Globals.h:35
@ EVENT_TEMPO_CHANGED
Definition EventQueue.h:103