hydrogen 1.2.3
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-2024 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
26
27#include <pthread.h>
28#include <unistd.h>
29
30//currently H2CORE_HAVE_OSC means: liblo is present..
31#if defined(H2CORE_HAVE_OSC) || _DOXYGEN_
32
33#include <lo/lo.h>
34#include <lo/lo_cpp.h>
35
37#include "core/OscServer.h"
39#include "core/EventQueue.h"
40#include "core/Hydrogen.h"
42#include "core/Basics/Song.h"
43#include "core/MidiAction.h"
44
46
47
48QString OscServer::qPrettyPrint(lo_type type,void * data)
49{
50 QString formattedString;
51
52 typedef union {
53 int32_t i;
54 float f;
55 char c;
56 uint32_t nl;
57 } h2_pcast32;
58
59 typedef union {
60 int64_t i;
61 double f;
62 uint64_t nl;
63 } h2_pcast64;
64
65
66 h2_pcast32 val32 = {0};
67 h2_pcast64 val64 = {0};
68 int size;
69
70 size = lo_arg_size(type, data);
71 if (size == 4 || type == LO_BLOB) {
72 val32.nl = *(int32_t *)data;
73 } else if (size == 8) {
74 val64.nl = *(int64_t *)data;
75 } else {
76 //error case
77 formattedString = QString("Unhandled size: %1").arg(size);
78
79 return formattedString;
80 }
81
82 switch (type) {
83 case LO_INT32:
84 formattedString = QString("%1").arg(val32.i);
85 break;
86
87 case LO_FLOAT:
88 formattedString = QString("%1").arg(val32.f);
89 break;
90
91 case LO_STRING:
92 formattedString = QString("%1").arg( (char *) data );
93 break;
94
95 case LO_BLOB:
96 //not supported by Hydrogen
97 formattedString = QString("BLOB");
98 break;
99
100 case LO_INT64:
101 formattedString = QString("%1").arg(val64.i);
102 break;
103
104 case LO_DOUBLE:
105 formattedString = QString("%1").arg(val64.f);
106 break;
107
108 case LO_SYMBOL:
109 formattedString = QString("%1").arg( (char *) data );
110 break;
111
112 case LO_CHAR:
113 formattedString = QString("%1").arg( QLatin1Char((char) val32.c ));
114 break;
115
116 case LO_MIDI:
117 //not supported by Hydrogen
118 formattedString = QString("MIDI");
119 break;
120
121 case LO_TRUE:
122 formattedString = QString("#T");
123 break;
124
125 case LO_FALSE:
126 formattedString = QString("#F");
127 break;
128
129 case LO_NIL:
130 formattedString = QString("#NIL");
131 break;
132
133 case LO_INFINITUM:
134 formattedString = QString("#INF");
135 break;
136
137 case LO_TIMETAG:
138 default:
139 formattedString = QString("Unhandled type:").arg(type);
140 break;
141 }
142
143 return formattedString;
144
145}
146
147/* catch any incoming messages and display them. returning 1 means that the
148 * message has not been fully handled and the server should try other methods */
150 const char * types,
151 lo_arg ** argv,
152 int argc,
153 lo_message data,
154 void * user_data) {
155
156 QString sSummary = QString( "Incoming OSC Message for path [%1]" ).arg( path );
157 for ( int ii = 0; ii < argc; ii++) {
158 QString formattedArgument = qPrettyPrint( (lo_type)types[ii], argv[ii] );
159 sSummary.append( QString( ", arg. %1: [%2, %3]" )
160 .arg( ii ).arg( types[ ii ] ).arg( formattedArgument ) );
161 }
162
163 INFOLOG( sSummary );
164
165 return 1;
166}
167
168int OscServer::generic_handler(const char * path,
169 const char * types,
170 lo_arg ** argv,
171 int argc,
172 lo_message data,
173 void * user_data)
174{
175 auto pHydrogen = H2Core::Hydrogen::get_instance();
176 auto pController = pHydrogen->getCoreActionController();
177 auto pSong = pHydrogen->getSong();
178
179 if ( pSong == nullptr ) {
180 ERRORLOG( "No song set yet" );
181 return 1;
182 }
183
184 bool bMessageProcessed = false;
185
186 int nNumberOfStrips = pSong->getInstrumentList()->size();
187
188 //First we're trying to map TouchOSC messages from multi-fader widgets
189 QString oscPath( path );
190 QRegExp rxStripVol( "/Hydrogen/STRIP_VOLUME_ABSOLUTE/(\\d+)" );
191 int pos = rxStripVol.indexIn( oscPath );
192 if ( pos > -1 ) {
193 if( argc == 1 ){
194 int nStrip = rxStripVol.cap(1).toInt() -1;
195 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
196 STRIP_VOLUME_ABSOLUTE_Handler( nStrip , argv[0]->f );
197 bMessageProcessed = true;
198 }
199 else {
200 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
201 .arg( nStrip + 1 ).arg( 1 )
202 .arg( nNumberOfStrips ) );
203 }
204 }
205 }
206
207 QRegExp rxStripVolRel( "/Hydrogen/STRIP_VOLUME_RELATIVE/(\\d+)" );
208 pos = rxStripVolRel.indexIn( oscPath );
209 if ( pos > -1 ) {
210 if( argc == 1 ){
211 int nStrip = rxStripVolRel.cap(1).toInt() - 1;
212 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
213 STRIP_VOLUME_RELATIVE_Handler( QString::number( nStrip ),
214 QString::number( argv[0]->f, 'f', 0 ) );
215 bMessageProcessed = true;
216 }
217 else {
218 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
219 .arg( nStrip + 1 ).arg( 1 )
220 .arg( nNumberOfStrips ) );
221 }
222 }
223 }
224
225 QRegExp rxStripPanAbs( "/Hydrogen/PAN_ABSOLUTE/(\\d+)" );
226 pos = rxStripPanAbs.indexIn( oscPath );
227 if ( pos > -1 ) {
228 if( argc == 1 ){
229 int nStrip = rxStripPanAbs.cap(1).toInt() - 1;
230 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
231 INFOLOG( QString( "processing message as changing pan of strip [%1] in absolute numbers" )
232 .arg( nStrip ) );
233 pController->setStripPan( nStrip, argv[0]->f, false );
234 bMessageProcessed = true;
235 }
236 else {
237 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
238 .arg( nStrip + 1 ).arg( 1 )
239 .arg( nNumberOfStrips ) );
240 }
241 }
242 }
243
244 QRegExp rxStripPanAbsSym( "/Hydrogen/PAN_ABSOLUTE_SYM/(\\d+)" );
245 pos = rxStripPanAbsSym.indexIn( oscPath );
246 if ( pos > -1 ) {
247 if( argc == 1 ){
248 int nStrip = rxStripPanAbsSym.cap(1).toInt() - 1;
249 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
250 INFOLOG( QString( "processing message as changing pan of strip [%1] in symmetric, absolute numbers" )
251 .arg( nStrip ) );
252 pController->setStripPanSym( nStrip, argv[0]->f, false );
253 bMessageProcessed = true;
254 }
255 else {
256 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
257 .arg( nStrip + 1 ).arg( 1 )
258 .arg( nNumberOfStrips ) );
259 }
260 }
261 }
262
263 QRegExp rxStripPanRel( "/Hydrogen/PAN_RELATIVE/(\\d+)" );
264 pos = rxStripPanRel.indexIn( oscPath );
265 if ( pos > -1 ) {
266 if( argc == 1 ){
267 int nStrip = rxStripPanRel.cap(1).toInt() - 1;
268 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
269 INFOLOG( QString( "processing message as changing pan of strip [%1] in relative numbers" )
270 .arg( nStrip ) );
271 std::shared_ptr<Action> pAction = std::make_shared<Action>("PAN_RELATIVE");
272 pAction->setParameter1( QString::number( nStrip ) );
273 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ) );
275 bMessageProcessed = true;
276 }
277 else {
278 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
279 .arg( nStrip + 1 ).arg( 1 )
280 .arg( nNumberOfStrips ) );
281 }
282 }
283 }
284
285 QRegExp rxStripFilterCutoffAbs( "/Hydrogen/FILTER_CUTOFF_LEVEL_ABSOLUTE/(\\d+)" );
286 pos = rxStripFilterCutoffAbs.indexIn( oscPath );
287 if ( pos > -1 ) {
288 if( argc == 1 ){
289 int nStrip = rxStripFilterCutoffAbs.cap(1).toInt() - 1;
290 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
291 FILTER_CUTOFF_LEVEL_ABSOLUTE_Handler( QString::number( nStrip ),
292 QString::number( argv[0]->f, 'f', 0 ) );
293 bMessageProcessed = true;
294 }
295 else {
296 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
297 .arg( nStrip + 1 ).arg( 1 )
298 .arg( nNumberOfStrips ) );
299 }
300 }
301 }
302
303 QRegExp rxStripMute( "/Hydrogen/STRIP_MUTE_TOGGLE/(\\d+)" );
304 pos = rxStripMute.indexIn( oscPath );
305 if ( pos > -1 ) {
306 if( argc <= 1 ){
307 int nStrip = rxStripMute.cap(1).toInt() - 1;
308 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
309 INFOLOG( QString( "processing message as toggling mute of strip [%1]" )
310 .arg( nStrip ) );
311 pController->toggleStripIsMuted( nStrip );
312 bMessageProcessed = true;
313 }
314 else {
315 ERRORLOG( QString( "Provided strip number [%1] out of bound [%2,%3]" )
316 .arg( nStrip + 1 ).arg( 1 )
317 .arg( nNumberOfStrips ) );
318 }
319 }
320 }
321
322 QRegExp rxStripSolo( "/Hydrogen/STRIP_SOLO_TOGGLE/(\\d+)" );
323 pos = rxStripSolo.indexIn( oscPath );
324 if ( pos > -1 ) {
325 if ( argc <= 1 ) {
326 int nStrip = rxStripSolo.cap(1).toInt() - 1;
327 if ( nStrip > -1 && nStrip < nNumberOfStrips ) {
328 INFOLOG( QString( "processing message as toggling solo of strip [%1]" )
329 .arg( nStrip ) );
330 pController->toggleStripIsSoloed( 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
341 if ( ! bMessageProcessed ) {
342 ERRORLOG( "No matching handler found" );
343 }
344
345 // Returning 1 means that the message has not been fully handled
346 // and the server should try other methods.
347 return 1;
348}
349
350
351
352OscServer::OscServer( H2Core::Preferences* pPreferences ) : m_bInitialized( false )
353{
354 m_pPreferences = pPreferences;
355
357 {
358 int port = m_pPreferences->getOscServerPort();
359
360 m_pServerThread = new lo::ServerThread( port );
361
362 // If there is already another service registered to the same
363 // port, the OSC server is not valid an can not be started.
364 if ( !m_pServerThread->is_valid() ) {
365 int tmpPort;
366
367 delete m_pServerThread;
368
369 // Instead, let the liblo library choose a working
370 // port on their own (nullptr argument).
371 m_pServerThread = new lo::ServerThread( nullptr );
372
373 tmpPort = m_pServerThread->port();
374
375 ERRORLOG( QString("Could not start OSC server on port %1, using port %2 instead.").arg(port).arg(tmpPort));
376
378
380 } else {
381 INFOLOG( QString( "OSC server running on port %1" ).arg( port ) );
382 }
383 } else {
384
385 m_pServerThread = nullptr;
386
387 }
388}
389
391
392 for (std::list<lo_address>::iterator it=m_pClientRegistry.begin(); it != m_pClientRegistry.end(); ++it){
393 lo_address_free( *it );
394 }
395
396 delete m_pServerThread;
397
398 __instance = nullptr;
399}
400
402{
403 if( __instance == nullptr ) {
404 __instance = new OscServer( pPreferences );
405 }
406}
407
408// -------------------------------------------------------------------
409// Handler functions
410
411void OscServer::PLAY_Handler(lo_arg **argv,int i)
412{
413 INFOLOG( "processing message" );
414 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY");
416
417 // Null song handling done in MidiActionManager.
418 pActionManager->handleAction( pAction );
419}
420
421void OscServer::PLAY_STOP_TOGGLE_Handler(lo_arg **argv,int i)
422{
423 INFOLOG( "processing message" );
424 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY/STOP_TOGGLE");
426
427 // Null song handling done in MidiActionManager.
428 pActionManager->handleAction( pAction );
429}
430
432{
433 INFOLOG( "processing message" );
434 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAY/PAUSE_TOGGLE");
436
437 // Null song handling done in MidiActionManager.
438 pActionManager->handleAction( pAction );
439}
440
441void OscServer::STOP_Handler(lo_arg **argv,int i)
442{
443 INFOLOG( "processing message" );
444 std::shared_ptr<Action> pAction = std::make_shared<Action>("STOP");
446
447 // Null song handling done in MidiActionManager.
448 pActionManager->handleAction( pAction );
449}
450
451void OscServer::PAUSE_Handler(lo_arg **argv,int i)
452{
453 INFOLOG( "processing message" );
454 std::shared_ptr<Action> pAction = std::make_shared<Action>("PAUSE");
456
457 // Null song handling done in MidiActionManager.
458 pActionManager->handleAction( pAction );
459}
460
461void OscServer::RECORD_READY_Handler(lo_arg **argv,int i)
462{
463 INFOLOG( "processing message" );
464 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_READY");
466
467 // Null song handling done in MidiActionManager.
468 pActionManager->handleAction( pAction );
469}
470
472{
473 INFOLOG( "processing message" );
474 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD/STROBE_TOGGLE");
476
477 // Null song handling done in MidiActionManager.
478 pActionManager->handleAction( pAction );
479}
480
481void OscServer::RECORD_STROBE_Handler(lo_arg **argv,int i)
482{
483 INFOLOG( "processing message" );
484 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_STROBE");
486
487 // Null song handling done in MidiActionManager.
488 pActionManager->handleAction( pAction );
489}
490
491void OscServer::RECORD_EXIT_Handler(lo_arg **argv,int i)
492{
493 INFOLOG( "processing message" );
494 std::shared_ptr<Action> pAction = std::make_shared<Action>("RECORD_EXIT");
496
497 // Null song handling done in MidiActionManager.
498 pActionManager->handleAction( pAction );
499}
500
501void OscServer::MUTE_Handler(lo_arg **argv,int i)
502{
503 INFOLOG( "processing message" );
504 std::shared_ptr<Action> pAction = std::make_shared<Action>("MUTE");
506
507 // Null song handling done in MidiActionManager.
508 pActionManager->handleAction( pAction );
509}
510
511void OscServer::UNMUTE_Handler(lo_arg **argv,int i)
512{
513 INFOLOG( "processing message" );
514 std::shared_ptr<Action> pAction = std::make_shared<Action>("UNMUTE");
516
517 // Null song handling done in MidiActionManager.
518 pActionManager->handleAction( pAction );
519}
520
521void OscServer::MUTE_TOGGLE_Handler(lo_arg **argv,int i)
522{
523 INFOLOG( "processing message" );
524 std::shared_ptr<Action> pAction = std::make_shared<Action>("MUTE_TOGGLE");
526
527 // Null song handling done in MidiActionManager.
528 pActionManager->handleAction( pAction );
529}
530
531void OscServer::NEXT_BAR_Handler(lo_arg **argv,int i)
532{
533 INFOLOG( "processing message" );
534 std::shared_ptr<Action> pAction = std::make_shared<Action>(">>_NEXT_BAR");
536
537 // Null song handling done in MidiActionManager.
538 pActionManager->handleAction( pAction );
539}
540
541void OscServer::PREVIOUS_BAR_Handler(lo_arg **argv,int i)
542{
543 INFOLOG( "processing message" );
544 std::shared_ptr<Action> pAction = std::make_shared<Action>("<<_PREVIOUS_BAR");
546
547 // Null song handling done in MidiActionManager.
548 pActionManager->handleAction( pAction );
549}
550
551void OscServer::BPM_Handler(lo_arg **argv,int i)
552{
553 INFOLOG( "processing message" );
554 auto pHydrogen = H2Core::Hydrogen::get_instance();
555 auto pAudioEngine = pHydrogen->getAudioEngine();
556
557 float fNewBpm = argv[0]->f;
558 fNewBpm = std::clamp( fNewBpm, static_cast<float>(MIN_BPM),
559 static_cast<float>(MAX_BPM) );
560
561 pAudioEngine->lock( RIGHT_HERE );
562 pAudioEngine->setNextBpm( fNewBpm );
563 pAudioEngine->unlock();
564
565 pHydrogen->getSong()->setBpm( fNewBpm );
566
567 pHydrogen->setIsModified( true );
568
570}
571
572void OscServer::BPM_INCR_Handler(lo_arg **argv,int i)
573{
574 INFOLOG( "processing message" );
575 std::shared_ptr<Action> pAction = std::make_shared<Action>("BPM_INCR");
577
578 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ));
579
580 // Null song handling done in MidiActionManager.
581 pActionManager->handleAction( pAction );
582}
583
584void OscServer::BPM_DECR_Handler(lo_arg **argv,int i)
585{
586 INFOLOG( "processing message" );
587 std::shared_ptr<Action> pAction = std::make_shared<Action>("BPM_DECR");
589
590 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ));
591
592 // Null song handling done in MidiActionManager.
593 pActionManager->handleAction( pAction );
594}
595
597{
598 INFOLOG( "processing message" );
600 H2Core::CoreActionController* pController = pHydrogen->getCoreActionController();
601
602 // Null song handling done in MidiActionManager.
603 pController->setMasterVolume( argv[0]->f );
604}
605
607{
608 INFOLOG( "processing message" );
609 std::shared_ptr<Action> pAction = std::make_shared<Action>("MASTER_VOLUME_RELATIVE");
610 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ));
612
613 // Null song handling done in MidiActionManager.
614 pActionManager->handleAction( pAction );
615}
616
617void OscServer::STRIP_VOLUME_ABSOLUTE_Handler(int param1, float param2)
618{
619 INFOLOG( "processing message" );
621 H2Core::CoreActionController* pController = pHydrogen->getCoreActionController();
622
623 // Null song handling done in MidiActionManager.
624 pController->setStripVolume( param1, param2, false );
625}
626
627void OscServer::STRIP_VOLUME_RELATIVE_Handler(QString param1, QString param2)
628{
629 INFOLOG( "processing message" );
630 std::shared_ptr<Action> pAction = std::make_shared<Action>("STRIP_VOLUME_RELATIVE");
631 pAction->setParameter1( param1 );
632 pAction->setValue( param2 );
634
635 // Null song handling done in MidiActionManager.
636 pActionManager->handleAction( pAction );
637}
638
640{
641 INFOLOG( "processing message" );
642 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_NEXT_PATTERN");
643 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
645
646 // Null song handling done in MidiActionManager.
647 pActionManager->handleAction( pAction );
648}
649
651{
652 INFOLOG( "processing message" );
653 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_ONLY_NEXT_PATTERN");
654 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
656
657 // Null song handling done in MidiActionManager.
658 pActionManager->handleAction( pAction );
659}
660
662{
663 INFOLOG( "processing message" );
664 std::shared_ptr<Action> pAction = std::make_shared<Action>("SELECT_AND_PLAY_PATTERN");
665 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
667
668 // Null song handling done in MidiActionManager.
669 pActionManager->handleAction( pAction );
670}
671
672void OscServer::FILTER_CUTOFF_LEVEL_ABSOLUTE_Handler(QString param1, QString param2)
673{
674 INFOLOG( "processing message" );
675 std::shared_ptr<Action> pAction = std::make_shared<Action>("FILTER_CUTOFF_LEVEL_ABSOLUTE");
676 pAction->setParameter1( param1 );
677 pAction->setValue( param2 );
679
680 // Null song handling done in MidiActionManager.
681 pActionManager->handleAction( pAction );
682}
683
684void OscServer::BEATCOUNTER_Handler(lo_arg **argv,int i)
685{
686 INFOLOG( "processing message" );
687 std::shared_ptr<Action> pAction = std::make_shared<Action>("BEATCOUNTER");
689
690 // Null song handling done in MidiActionManager.
691 pActionManager->handleAction( pAction );
692}
693
694void OscServer::TAP_TEMPO_Handler(lo_arg **argv,int i)
695{
696 INFOLOG( "processing message" );
697 std::shared_ptr<Action> pAction = std::make_shared<Action>("TAP_TEMPO");
699
700 // Null song handling done in MidiActionManager.
701 pActionManager->handleAction( pAction );
702}
703
704void OscServer::PLAYLIST_SONG_Handler(lo_arg **argv,int i)
705{
706 INFOLOG( "processing message" );
707 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_SONG");
708 pAction->setParameter1( QString::number( argv[0]->f, 'f', 0 ) );
709
711
712 // Null song handling done in MidiActionManager.
713 pActionManager->handleAction( pAction );
714}
715
717{
718 INFOLOG( "processing message" );
719 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_NEXT_SONG");
721
722 // Null song handling done in MidiActionManager.
723 pActionManager->handleAction( pAction );
724}
725
727{
728 INFOLOG( "processing message" );
729 std::shared_ptr<Action> pAction = std::make_shared<Action>("PLAYLIST_PREV_SONG");
731
732 // Null song handling done in MidiActionManager.
733 pActionManager->handleAction( pAction );
734}
735
736void OscServer::TOGGLE_METRONOME_Handler(lo_arg **argv,int i)
737{
738 INFOLOG( "processing message" );
739 std::shared_ptr<Action> pAction = std::make_shared<Action>("TOGGLE_METRONOME");
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>("SELECT_INSTRUMENT");
750 pAction->setValue( QString::number( argv[0]->f, 'f', 0 ) );
751
753
754 // Null song handling done in MidiActionManager.
755 pActionManager->handleAction( pAction );
756}
757
758void OscServer::UNDO_ACTION_Handler(lo_arg **argv,int i)
759{
760 INFOLOG( "processing message" );
761 std::shared_ptr<Action> pAction = std::make_shared<Action>("UNDO_ACTION");
763
764 // This one does also work the current song being nullptr.
765 pActionManager->handleAction( pAction );
766}
767
768void OscServer::REDO_ACTION_Handler(lo_arg **argv,int i)
769{
770 INFOLOG( "processing message" );
771 std::shared_ptr<Action> pAction = std::make_shared<Action>("REDO_ACTION");
773
774 // This one does also work the current song being nullptr.
775 pActionManager->handleAction( pAction );
776}
777
778// -------------------------------------------------------------------
779// Actions required for session management.
780
781void OscServer::NEW_SONG_Handler(lo_arg **argv, int argc) {
782 INFOLOG( "processing message" );
783 auto pHydrogen = H2Core::Hydrogen::get_instance();
784 auto pController = pHydrogen->getCoreActionController();
785 pController->newSong( QString::fromUtf8( &argv[0]->s ) );
786}
787
788void OscServer::OPEN_SONG_Handler(lo_arg **argv, int argc) {
789 INFOLOG( "processing message" );
790 auto pHydrogen = H2Core::Hydrogen::get_instance();
791 auto pController = pHydrogen->getCoreActionController();
792 pController->openSong( QString::fromUtf8( &argv[0]->s ) );
793}
794
795void OscServer::SAVE_SONG_Handler(lo_arg **argv, int argc) {
796 INFOLOG( "processing message" );
797 auto pHydrogen = H2Core::Hydrogen::get_instance();
798 if ( pHydrogen->getSong() == nullptr ) {
799 ERRORLOG( "No song set yet" );
800 return;
801 }
802
803 auto pController = pHydrogen->getCoreActionController();
804 pController->saveSong();
805}
806
807void OscServer::SAVE_SONG_AS_Handler(lo_arg **argv, int argc) {
808 INFOLOG( "processing message" );
809 auto pHydrogen = H2Core::Hydrogen::get_instance();
810 if ( pHydrogen->getSong() == nullptr ) {
811 ERRORLOG( "No song set yet" );
812 return;
813 }
814
815 auto pController = pHydrogen->getCoreActionController();
816 pController->saveSongAs( QString::fromUtf8( &argv[0]->s ) );
817}
818
819void OscServer::SAVE_PREFERENCES_Handler(lo_arg **argv, int argc) {
820 INFOLOG( "processing message" );
821 auto pHydrogen = H2Core::Hydrogen::get_instance();
822 if ( pHydrogen->getSong() == nullptr ) {
823 ERRORLOG( "No song set yet" );
824 return;
825 }
826
827 auto pController = pHydrogen->getCoreActionController();
828 pController->savePreferences();
829}
830
831void OscServer::QUIT_Handler(lo_arg **argv, int argc) {
832 INFOLOG( "processing message" );
833 auto pHydrogen = H2Core::Hydrogen::get_instance();
834 auto pController = pHydrogen->getCoreActionController();
835 pController->quit();
836}
837
838// -------------------------------------------------------------------
839
840void OscServer::TIMELINE_ACTIVATION_Handler(lo_arg **argv, int argc) {
841 INFOLOG( "processing message" );
842 auto pHydrogen = H2Core::Hydrogen::get_instance();
843 if ( pHydrogen->getSong() == nullptr ) {
844 ERRORLOG( "No song set yet" );
845 return;
846 }
847
848 auto pController = pHydrogen->getCoreActionController();
849
850 if ( argv[0]->f != 0 ) {
851 pController->activateTimeline( true );
852 } else {
853 pController->activateTimeline( false );
854 }
855}
856
857void OscServer::TIMELINE_ADD_MARKER_Handler(lo_arg **argv, int argc) {
858 INFOLOG( "processing message" );
859 auto pHydrogen = H2Core::Hydrogen::get_instance();
860 if ( pHydrogen->getSong() == nullptr ) {
861 ERRORLOG( "No song set yet" );
862 return;
863 }
864
865 auto pController = pHydrogen->getCoreActionController();
866 pController->addTempoMarker( static_cast<int>(std::round( argv[0]->f )),
867 argv[1]->f);
868}
869
870void OscServer::TIMELINE_DELETE_MARKER_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 pController->deleteTempoMarker( static_cast<int>( std::round( argv[0]->f ) ) );
880}
881
882void OscServer::JACK_TRANSPORT_ACTIVATION_Handler(lo_arg **argv, int argc) {
883 INFOLOG( "processing message" );
884 auto pHydrogen = H2Core::Hydrogen::get_instance();
885 if ( pHydrogen->getSong() == nullptr ) {
886 ERRORLOG( "No song set yet" );
887 return;
888 }
889
890 auto pController = pHydrogen->getCoreActionController();
891
892 if ( argv[0]->f != 0 ) {
893 pController->activateJackTransport( true );
894 } else {
895 pController->activateJackTransport( false );
896 }
897}
898
900 INFOLOG( "processing message" );
901 auto pHydrogen = H2Core::Hydrogen::get_instance();
902 if ( pHydrogen->getSong() == nullptr ) {
903 ERRORLOG( "No song set yet" );
904 return;
905 }
906
907 auto pController = pHydrogen->getCoreActionController();
908 if ( argv[0]->f != 0 ) {
909 pController->activateJackTimebaseMaster( true );
910 } else {
911 pController->activateJackTimebaseMaster( false );
912 }
913}
914
915void OscServer::SONG_MODE_ACTIVATION_Handler(lo_arg **argv, int argc) {
916 INFOLOG( "processing message" );
917 auto pHydrogen = H2Core::Hydrogen::get_instance();
918 if ( pHydrogen->getSong() == nullptr ) {
919 ERRORLOG( "No song set yet" );
920 return;
921 }
922
923 auto pController = pHydrogen->getCoreActionController();
924 if ( argv[0]->f != 0 ) {
925 pController->activateSongMode( true );
926 } else {
927 pController->activateSongMode( false );
928 }
929}
930
931void OscServer::LOOP_MODE_ACTIVATION_Handler(lo_arg **argv, int argc) {
932 INFOLOG( "processing message" );
933 auto pHydrogen = H2Core::Hydrogen::get_instance();
934 if ( pHydrogen->getSong() == nullptr ) {
935 ERRORLOG( "No song set yet" );
936 return;
937 }
938
939 auto pController = pHydrogen->getCoreActionController();
940 if ( argv[0]->f != 0 ) {
941 pController->activateLoopMode( true );
942 } else {
943 pController->activateLoopMode( false );
944 }
945}
946
947void OscServer::RELOCATE_Handler(lo_arg **argv, int argc) {
948 INFOLOG( "processing message" );
949 auto pHydrogen = H2Core::Hydrogen::get_instance();
950 if ( pHydrogen->getSong() == nullptr ) {
951 ERRORLOG( "No song set yet" );
952 return;
953 }
954
955 pHydrogen->getCoreActionController()->locateToColumn( static_cast<int>(std::round( argv[0]->f ) ) );
956}
957
958void OscServer::NEW_PATTERN_Handler(lo_arg **argv, int argc) {
959 INFOLOG( "processing message" );
960 auto pHydrogen = H2Core::Hydrogen::get_instance();
961 if ( pHydrogen->getSong() == nullptr ) {
962 ERRORLOG( "No song set yet" );
963 return;
964 }
965
966 auto pController = pHydrogen->getCoreActionController();
967 pController->newPattern( QString::fromUtf8( &argv[0]->s ) );
968}
969
970void OscServer::OPEN_PATTERN_Handler(lo_arg **argv, int argc) {
971 INFOLOG( "processing message" );
972 auto pHydrogen = H2Core::Hydrogen::get_instance();
973 if ( pHydrogen->getSong() == nullptr ) {
974 ERRORLOG( "No song set yet" );
975 return;
976 }
977
978 auto pController = pHydrogen->getCoreActionController();
979 pController->openPattern( QString::fromUtf8( &argv[0]->s ) );
980}
981
982void OscServer::REMOVE_PATTERN_Handler(lo_arg **argv, int argc) {
983 INFOLOG( "processing message" );
984 auto pHydrogen = H2Core::Hydrogen::get_instance();
985 if ( pHydrogen->getSong() == nullptr ) {
986 ERRORLOG( "No song set yet" );
987 return;
988 }
989
990 auto pController = pHydrogen->getCoreActionController();
991 pController->removePattern( static_cast<int>(std::round( argv[0]->f )) );
992}
993
995 INFOLOG( "processing message" );
996 auto pHydrogen = H2Core::Hydrogen::get_instance();
997 if ( pHydrogen->getSong() == nullptr ) {
998 ERRORLOG( "No song set yet" );
999 return;
1000 }
1001
1002 auto pController = pHydrogen->getCoreActionController();
1003 pController->toggleGridCell( static_cast<int>(std::round( argv[0]->f )),
1004 static_cast<int>(std::round( argv[1]->f )) );
1005}
1006
1007void OscServer::LOAD_DRUMKIT_Handler(lo_arg **argv, int argc) {
1008 INFOLOG( "processing message" );
1009 auto pHydrogen = H2Core::Hydrogen::get_instance();
1010 if ( pHydrogen->getSong() == nullptr ) {
1011 ERRORLOG( "No song set yet" );
1012 return;
1013 }
1014
1015 auto pController = pHydrogen->getCoreActionController();
1016
1017 bool bConditionalLoad = true;
1018 if ( argc > 1 ) {
1019 bConditionalLoad = argv[1]->f == 0 ? false : true;
1020 }
1021
1022 pController->setDrumkit( QString::fromUtf8( &argv[0]->s ),
1023 bConditionalLoad );
1024}
1025
1026void OscServer::UPGRADE_DRUMKIT_Handler(lo_arg **argv, int argc) {
1027 INFOLOG( "processing message" );
1028
1030
1031 QString sNewPath = "";
1032 if ( argc > 1 ) {
1033 sNewPath = QString::fromUtf8( &argv[1]->s );
1034 }
1035
1036 pController->upgradeDrumkit( QString::fromUtf8( &argv[0]->s ),
1037 sNewPath );
1038}
1039
1040void OscServer::VALIDATE_DRUMKIT_Handler(lo_arg **argv, int argc) {
1041 INFOLOG( "processing message" );
1042
1043 bool bValidateLegacyKits = false;
1044 if ( argc > 1 ) {
1045 bValidateLegacyKits = argv[1]->f == 0 ? false : true;
1046 }
1047
1049 pController->validateDrumkit( QString::fromUtf8( &argv[0]->s ),
1050 bValidateLegacyKits );
1051}
1052
1053void OscServer::EXTRACT_DRUMKIT_Handler(lo_arg **argv, int argc) {
1054 INFOLOG( "processing message" );
1055
1057
1058 QString sTargetDir = "";
1059 if ( argc > 1 ) {
1060 sTargetDir = QString::fromUtf8( &argv[1]->s );
1061 }
1062
1063 pController->extractDrumkit( QString::fromUtf8( &argv[0]->s ), sTargetDir );
1064}
1065
1066// -------------------------------------------------------------------
1067// Helper functions
1068
1069bool IsLoAddressEqual( lo_address first, lo_address second )
1070{
1071 bool portEqual = ( strcmp( lo_address_get_port( first ), lo_address_get_port( second ) ) == 0);
1072 bool hostEqual = ( strcmp( lo_address_get_hostname( first ), lo_address_get_hostname( second ) ) == 0);
1073 bool protoEqual = ( lo_address_get_protocol( first ) == lo_address_get_protocol( second ) );
1074
1075 return portEqual && hostEqual && protoEqual;
1076}
1077
1078void OscServer::broadcastMessage( const char* msgText, lo_message message ) {
1079 for ( const auto& clientAddress: m_pClientRegistry ){
1080
1081 INFOLOG( QString( "Outgoing OSC broadcast message %1" ).arg( msgText ));
1082
1083 int i;
1084 for (i = 0; i < lo_message_get_argc( message ); i++) {
1085 QString formattedArgument = qPrettyPrint( (lo_type)lo_message_get_types(message)[i], lo_message_get_argv(message)[i] );
1086 INFOLOG(QString("Argument %1: %2 %3").arg(i).arg(lo_message_get_types(message)[i]).arg(formattedArgument));
1087 }
1088
1089 lo_send_message(clientAddress, msgText, message);
1090 }
1091}
1092
1093// -------------------------------------------------------------------
1094// Main action handler
1095
1096void OscServer::handleAction( std::shared_ptr<Action> pAction )
1097{
1099
1100 if( !pPref->getOscFeedbackEnabled() ){
1101 return;
1102 }
1103
1104 if( pAction->getType() == "MASTER_VOLUME_ABSOLUTE"){
1105 bool ok;
1106 float fValue = pAction->getValue().toFloat(&ok);
1107
1108 lo_message reply = lo_message_new();
1109 lo_message_add_float( reply, fValue );
1110
1111 broadcastMessage("/Hydrogen/MASTER_VOLUME_ABSOLUTE", reply);
1112
1113 lo_message_free( reply );
1114 }
1115
1116 if( pAction->getType() == "STRIP_VOLUME_ABSOLUTE"){
1117 bool ok;
1118 float fValue = pAction->getValue().toFloat(&ok);
1119
1120 lo_message reply = lo_message_new();
1121 lo_message_add_float( reply, fValue );
1122
1123 QByteArray ba = QString("/Hydrogen/STRIP_VOLUME_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1124 const char *c_str2 = ba.data();
1125
1126 broadcastMessage( c_str2, reply);
1127
1128 lo_message_free( reply );
1129 }
1130
1131 if( pAction->getType() == "TOGGLE_METRONOME"){
1132 bool ok;
1133 float param1 = pAction->getParameter1().toFloat(&ok);
1134
1135 lo_message reply = lo_message_new();
1136 lo_message_add_float(reply, param1);
1137
1138 broadcastMessage("/Hydrogen/TOGGLE_METRONOME", reply);
1139
1140 lo_message_free( reply );
1141 }
1142
1143 if( pAction->getType() == "MUTE_TOGGLE"){
1144 bool ok;
1145 float param1 = pAction->getParameter1().toFloat(&ok);
1146
1147 lo_message reply = lo_message_new();
1148 lo_message_add_float(reply, param1);
1149
1150 broadcastMessage("/Hydrogen/MUTE_TOGGLE", reply);
1151
1152 lo_message_free( reply );
1153 }
1154
1155 if( pAction->getType() == "STRIP_MUTE_TOGGLE"){
1156 bool ok;
1157 float fValue = pAction->getValue().toFloat(&ok);
1158
1159 lo_message reply = lo_message_new();
1160 lo_message_add_float( reply, fValue );
1161
1162 QByteArray ba = QString("/Hydrogen/STRIP_MUTE_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1163 const char *c_str2 = ba.data();
1164
1165 broadcastMessage( c_str2, reply);
1166
1167 lo_message_free( reply );
1168 }
1169
1170 if( pAction->getType() == "STRIP_SOLO_TOGGLE"){
1171 bool ok;
1172 float fValue = pAction->getValue().toFloat(&ok);
1173
1174 lo_message reply = lo_message_new();
1175 lo_message_add_float( reply, fValue );
1176
1177 QByteArray ba = QString("/Hydrogen/STRIP_SOLO_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1178 const char *c_str2 = ba.data();
1179
1180 broadcastMessage( c_str2, reply);
1181
1182 lo_message_free( reply );
1183 }
1184
1185 if( pAction->getType() == "PAN_ABSOLUTE"){
1186 bool ok;
1187 float fValue = pAction->getValue().toFloat(&ok);
1188
1189 lo_message reply = lo_message_new();
1190 lo_message_add_float( reply, fValue );
1191
1192 QByteArray ba = QString("/Hydrogen/PAN_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1193 const char *c_str2 = ba.data();
1194
1195 broadcastMessage( c_str2, reply);
1196
1197 lo_message_free( reply );
1198 }
1199
1200 if( pAction->getType() == "PAN_ABSOLUTE_SYM"){
1201 bool ok;
1202 float fValue = pAction->getValue().toFloat(&ok);
1203
1204 lo_message reply = lo_message_new();
1205 lo_message_add_float( reply, fValue );
1206
1207 QByteArray ba = QString("/Hydrogen/PAN_ABSOLUTE_SYM/%1").arg(pAction->getParameter1()).toLatin1();
1208 const char *c_str2 = ba.data();
1209
1210 broadcastMessage( c_str2, reply);
1211
1212 lo_message_free( reply );
1213 }
1214}
1215
1217{
1218 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1219 ERRORLOG("Failed to initialize OSC server. No valid server thread.");
1220 return false;
1221 }
1222
1223 /*
1224 * Register all handler functions
1225 */
1226
1227 //This handler is responsible for registering clients
1228 m_pServerThread->add_method(nullptr, nullptr, [&](lo_message msg){
1229 lo_address address = lo_message_get_source(msg);
1230
1231 bool AddressRegistered = false;
1232 for ( const auto& cclientAddress : m_pClientRegistry ){
1233 if ( IsLoAddressEqual( address, cclientAddress ) ) {
1234 AddressRegistered = true;
1235 break;
1236 }
1237 }
1238
1239 if( ! AddressRegistered ){
1240 lo_address newAddress =
1241 lo_address_new_with_proto( lo_address_get_protocol( address ),
1242 lo_address_get_hostname( address ),
1243 lo_address_get_port( address ) );
1244 m_pClientRegistry.push_back( newAddress );
1245 INFOLOG( QString( "New OSC client registered. Hostname: %1, port: %2, protocol: %3" )
1246 .arg( lo_address_get_hostname( address ) )
1247 .arg( lo_address_get_port( address ) )
1248 .arg( lo_address_get_protocol( address ) ) );
1249
1252 }
1253
1254 // Returning 1 means that the
1255 // message has not been fully
1256 // handled and the server should
1257 // try other methods.
1258 return 1;
1259 });
1260
1261 m_pServerThread->add_method(nullptr, nullptr, incomingMessageLogging, nullptr);
1262
1263 m_pServerThread->add_method("/Hydrogen/PLAY", "", PLAY_Handler);
1264 m_pServerThread->add_method("/Hydrogen/PLAY", "f", PLAY_Handler);
1265 m_pServerThread->add_method("/Hydrogen/PLAY_STOP_TOGGLE", "", PLAY_STOP_TOGGLE_Handler);
1266 m_pServerThread->add_method("/Hydrogen/PLAY_STOP_TOGGLE", "f", PLAY_STOP_TOGGLE_Handler);
1267 m_pServerThread->add_method("/Hydrogen/PLAY_PAUSE_TOGGLE", "", PLAY_PAUSE_TOGGLE_Handler);
1268 m_pServerThread->add_method("/Hydrogen/PLAY_PAUSE_TOGGLE", "f", PLAY_PAUSE_TOGGLE_Handler);
1269 m_pServerThread->add_method("/Hydrogen/STOP", "", STOP_Handler);
1270 m_pServerThread->add_method("/Hydrogen/STOP", "f", STOP_Handler);
1271 m_pServerThread->add_method("/Hydrogen/PAUSE", "", PAUSE_Handler);
1272 m_pServerThread->add_method("/Hydrogen/PAUSE", "f", PAUSE_Handler);
1273
1274 m_pServerThread->add_method("/Hydrogen/RECORD_READY", "", RECORD_READY_Handler);
1275 m_pServerThread->add_method("/Hydrogen/RECORD_READY", "f", RECORD_READY_Handler);
1276 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE_TOGGLE", "", RECORD_STROBE_TOGGLE_Handler);
1277 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE_TOGGLE", "f", RECORD_STROBE_TOGGLE_Handler);
1278 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE", "", RECORD_STROBE_Handler);
1279 m_pServerThread->add_method("/Hydrogen/RECORD_STROBE", "f", RECORD_STROBE_Handler);
1280 m_pServerThread->add_method("/Hydrogen/RECORD_EXIT", "", RECORD_EXIT_Handler);
1281 m_pServerThread->add_method("/Hydrogen/RECORD_EXIT", "f", RECORD_EXIT_Handler);
1282
1283 m_pServerThread->add_method("/Hydrogen/MUTE", "", MUTE_Handler);
1284 m_pServerThread->add_method("/Hydrogen/MUTE", "f", MUTE_Handler);
1285 m_pServerThread->add_method("/Hydrogen/UNMUTE", "", UNMUTE_Handler);
1286 m_pServerThread->add_method("/Hydrogen/UNMUTE", "f", UNMUTE_Handler);
1287 m_pServerThread->add_method("/Hydrogen/MUTE_TOGGLE", "", MUTE_TOGGLE_Handler);
1288 m_pServerThread->add_method("/Hydrogen/MUTE_TOGGLE", "f", MUTE_TOGGLE_Handler);
1289
1290 m_pServerThread->add_method("/Hydrogen/NEXT_BAR", "", NEXT_BAR_Handler);
1291 m_pServerThread->add_method("/Hydrogen/NEXT_BAR", "f", NEXT_BAR_Handler);
1292 m_pServerThread->add_method("/Hydrogen/PREVIOUS_BAR", "", PREVIOUS_BAR_Handler);
1293 m_pServerThread->add_method("/Hydrogen/PREVIOUS_BAR", "f", PREVIOUS_BAR_Handler);
1294
1295 m_pServerThread->add_method("/Hydrogen/BPM", "f", BPM_Handler);
1296 m_pServerThread->add_method("/Hydrogen/BPM_DECR", "f", BPM_DECR_Handler);
1297 m_pServerThread->add_method("/Hydrogen/BPM_INCR", "f", BPM_INCR_Handler);
1298
1299 m_pServerThread->add_method("/Hydrogen/MASTER_VOLUME_ABSOLUTE", "f", MASTER_VOLUME_ABSOLUTE_Handler);
1300 m_pServerThread->add_method("/Hydrogen/MASTER_VOLUME_RELATIVE", "f", MASTER_VOLUME_RELATIVE_Handler);
1301
1302 m_pServerThread->add_method("/Hydrogen/SELECT_NEXT_PATTERN", "f", SELECT_NEXT_PATTERN_Handler);
1303 m_pServerThread->add_method("/Hydrogen/SELECT_ONLY_NEXT_PATTERN", "f", SELECT_ONLY_NEXT_PATTERN_Handler);
1304 m_pServerThread->add_method("/Hydrogen/SELECT_AND_PLAY_PATTERN", "f", SELECT_AND_PLAY_PATTERN_Handler);
1305
1306 m_pServerThread->add_method("/Hydrogen/BEATCOUNTER", "", BEATCOUNTER_Handler);
1307 m_pServerThread->add_method("/Hydrogen/BEATCOUNTER", "f", BEATCOUNTER_Handler);
1308
1309 m_pServerThread->add_method("/Hydrogen/TAP_TEMPO", "", TAP_TEMPO_Handler);
1310 m_pServerThread->add_method("/Hydrogen/TAP_TEMPO", "f", TAP_TEMPO_Handler);
1311
1312 m_pServerThread->add_method("/Hydrogen/PLAYLIST_SONG", "f", PLAYLIST_SONG_Handler);
1313 m_pServerThread->add_method("/Hydrogen/PLAYLIST_NEXT_SONG", "", PLAYLIST_NEXT_SONG_Handler);
1314 m_pServerThread->add_method("/Hydrogen/PLAYLIST_NEXT_SONG", "f", PLAYLIST_NEXT_SONG_Handler);
1315 m_pServerThread->add_method("/Hydrogen/PLAYLIST_PREV_SONG", "", PLAYLIST_PREV_SONG_Handler);
1316 m_pServerThread->add_method("/Hydrogen/PLAYLIST_PREV_SONG", "f", PLAYLIST_PREV_SONG_Handler);
1317
1318 m_pServerThread->add_method("/Hydrogen/TOGGLE_METRONOME", "", TOGGLE_METRONOME_Handler);
1319 m_pServerThread->add_method("/Hydrogen/TOGGLE_METRONOME", "f", TOGGLE_METRONOME_Handler);
1320
1321 m_pServerThread->add_method("/Hydrogen/SELECT_INSTRUMENT", "f", SELECT_INSTRUMENT_Handler);
1322
1323 m_pServerThread->add_method("/Hydrogen/UNDO_ACTION", "", UNDO_ACTION_Handler);
1324 m_pServerThread->add_method("/Hydrogen/UNDO_ACTION", "f", UNDO_ACTION_Handler);
1325 m_pServerThread->add_method("/Hydrogen/REDO_ACTION", "", REDO_ACTION_Handler);
1326 m_pServerThread->add_method("/Hydrogen/REDO_ACTION", "f", REDO_ACTION_Handler);
1327
1328 m_pServerThread->add_method("/Hydrogen/NEW_SONG", "s", NEW_SONG_Handler);
1329 m_pServerThread->add_method("/Hydrogen/OPEN_SONG", "s", OPEN_SONG_Handler);
1330 m_pServerThread->add_method("/Hydrogen/SAVE_SONG", "", SAVE_SONG_Handler);
1331 m_pServerThread->add_method("/Hydrogen/SAVE_SONG", "f", SAVE_SONG_Handler);
1332 m_pServerThread->add_method("/Hydrogen/SAVE_SONG_AS", "s", SAVE_SONG_AS_Handler);
1333 m_pServerThread->add_method("/Hydrogen/SAVE_PREFERENCES", "", SAVE_SONG_Handler);
1334 m_pServerThread->add_method("/Hydrogen/SAVE_PREFERENCES", "f", SAVE_SONG_Handler);
1335 m_pServerThread->add_method("/Hydrogen/QUIT", "", QUIT_Handler);
1336 m_pServerThread->add_method("/Hydrogen/QUIT", "f", QUIT_Handler);
1337
1338 m_pServerThread->add_method("/Hydrogen/TIMELINE_ACTIVATION", "f", TIMELINE_ACTIVATION_Handler);
1339 m_pServerThread->add_method("/Hydrogen/TIMELINE_ADD_MARKER", "ff", TIMELINE_ADD_MARKER_Handler);
1340 m_pServerThread->add_method("/Hydrogen/TIMELINE_DELETE_MARKER", "f", TIMELINE_DELETE_MARKER_Handler);
1341
1342 m_pServerThread->add_method("/Hydrogen/JACK_TRANSPORT_ACTIVATION", "f", JACK_TRANSPORT_ACTIVATION_Handler);
1343 m_pServerThread->add_method("/Hydrogen/JACK_TIMEBASE_MASTER_ACTIVATION", "f", JACK_TIMEBASE_MASTER_ACTIVATION_Handler);
1344 m_pServerThread->add_method("/Hydrogen/SONG_MODE_ACTIVATION", "f", SONG_MODE_ACTIVATION_Handler);
1345 m_pServerThread->add_method("/Hydrogen/LOOP_MODE_ACTIVATION", "f", LOOP_MODE_ACTIVATION_Handler);
1346 m_pServerThread->add_method("/Hydrogen/RELOCATE", "f", RELOCATE_Handler);
1347 m_pServerThread->add_method("/Hydrogen/NEW_PATTERN", "s", NEW_PATTERN_Handler);
1348 m_pServerThread->add_method("/Hydrogen/OPEN_PATTERN", "s", OPEN_PATTERN_Handler);
1349 m_pServerThread->add_method("/Hydrogen/REMOVE_PATTERN", "f", REMOVE_PATTERN_Handler);
1350 m_pServerThread->add_method("/Hydrogen/SONG_EDITOR_TOGGLE_GRID_CELL", "ff", SONG_EDITOR_TOGGLE_GRID_CELL_Handler);
1351 m_pServerThread->add_method("/Hydrogen/LOAD_DRUMKIT", "s", LOAD_DRUMKIT_Handler);
1352 m_pServerThread->add_method("/Hydrogen/LOAD_DRUMKIT", "sf", LOAD_DRUMKIT_Handler);
1353 m_pServerThread->add_method("/Hydrogen/UPGRADE_DRUMKIT", "s", UPGRADE_DRUMKIT_Handler);
1354 m_pServerThread->add_method("/Hydrogen/UPGRADE_DRUMKIT", "ss", UPGRADE_DRUMKIT_Handler);
1355 m_pServerThread->add_method("/Hydrogen/VALIDATE_DRUMKIT", "s", VALIDATE_DRUMKIT_Handler);
1356 m_pServerThread->add_method("/Hydrogen/VALIDATE_DRUMKIT", "sf", VALIDATE_DRUMKIT_Handler);
1357 m_pServerThread->add_method("/Hydrogen/EXTRACT_DRUMKIT", "s", EXTRACT_DRUMKIT_Handler);
1358 m_pServerThread->add_method("/Hydrogen/EXTRACT_DRUMKIT", "ss", EXTRACT_DRUMKIT_Handler);
1359
1360 m_pServerThread->add_method(nullptr, nullptr, generic_handler, nullptr);
1361
1362 m_bInitialized = true;
1363
1364 return true;
1365}
1366
1368 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1369 ERRORLOG("Failed to start OSC server. No valid server thread.");
1370 return false;
1371 }
1372
1373 if ( ! m_bInitialized ) {
1374 if ( ! init() ) {
1375 return false;
1376 }
1377 }
1378
1379 m_pServerThread->start();
1380
1381 int nOscPortUsed;
1382 if ( m_pPreferences->m_nOscTemporaryPort != -1 ) {
1383 nOscPortUsed = m_pPreferences->m_nOscTemporaryPort;
1384 } else {
1385 nOscPortUsed = m_pPreferences->getOscServerPort();
1386 }
1387
1388 INFOLOG(QString("Osc server started. Listening on port %1").arg( nOscPortUsed ));
1389
1390 return true;
1391}
1392
1394 if ( m_pServerThread == nullptr || !m_pServerThread->is_valid() ) {
1395 ERRORLOG("Failed to stop OSC server. No valid server thread.");
1396 return false;
1397 }
1398
1399 m_pServerThread->stop();
1400 INFOLOG(QString("Osc server stopped" ));
1401
1402 return true;
1403}
1404
1405#endif /* H2CORE_HAVE_OSC */
1406
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:59
#define INFOLOG(x)
Definition Object.h:237
#define ERRORLOG(x)
Definition Object.h:239
bool IsLoAddressEqual(lo_address first, lo_address second)
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 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:83
@ OSC_CANNOT_CONNECT_TO_PORT
Unable to start the OSC server with the given port number.
Definition Hydrogen.h:283
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:639
Manager for User Preferences File (singleton)
Definition Preferences.h:78
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
int m_nOscTemporaryPort
In case m_nOscServerPort is already occupied by another client, the alternative - random - port numbe...
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:252
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:864
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:883
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 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:859
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::activateJackTimebaseMaster().
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:48
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 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:872
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 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 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 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...
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
@ EVENT_ERROR
Definition EventQueue.h:87