23#include <QRegularExpression>
32#if defined(H2CORE_HAVE_OSC) || _DOXYGEN_
52 QString formattedString;
68 h2_pcast32 val32 = {0};
69 h2_pcast64 val64 = {0};
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;
79 formattedString = QString(
"Unhandled size: %1").arg(size);
81 return formattedString;
86 formattedString = QString(
"%1").arg(val32.i);
90 formattedString = QString(
"%1").arg(val32.f);
94 formattedString = QString(
"%1").arg( (
char *) data );
99 formattedString = QString(
"BLOB");
103 formattedString = QString(
"%1").arg(val64.i);
107 formattedString = QString(
"%1").arg(val64.f);
111 formattedString = QString(
"%1").arg( (
char *) data );
115 formattedString = QString(
"%1").arg( QLatin1Char((
char) val32.c ));
120 formattedString = QString(
"MIDI");
124 formattedString = QString(
"#T");
128 formattedString = QString(
"#F");
132 formattedString = QString(
"#NIL");
136 formattedString = QString(
"#INF");
141 formattedString = QString(
"Unhandled type:").arg(type);
145 return formattedString;
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 ) );
178 auto pController = pHydrogen->getCoreActionController();
179 auto pSong = pHydrogen->getSong();
181 if ( pSong ==
nullptr ) {
186 bool bMessageProcessed =
false;
188 const int nNumberOfStrips = pSong->getInstrumentList()->size();
191 const QString oscPath( path );
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 ) {
203 bMessageProcessed =
true;
206 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
207 .arg( nStrip + 1 ).arg( 1 )
208 .arg( nNumberOfStrips ) );
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 ) {
222 QString::number( argv[0]->f,
'f', 0 ) );
223 bMessageProcessed =
true;
226 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
227 .arg( nStrip + 1 ).arg( 1 )
228 .arg( nNumberOfStrips ) );
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" )
243 pController->setStripPan( nStrip, argv[0]->f,
false );
244 bMessageProcessed =
true;
247 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
248 .arg( nStrip + 1 ).arg( 1 )
249 .arg( nNumberOfStrips ) );
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" )
264 pController->setStripPanSym( nStrip, argv[0]->f,
false );
265 bMessageProcessed =
true;
268 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
269 .arg( nStrip + 1 ).arg( 1 )
270 .arg( nNumberOfStrips ) );
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" )
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;
292 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
293 .arg( nStrip + 1 ).arg( 1 )
294 .arg( nNumberOfStrips ) );
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;
313 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
314 .arg( nStrip + 1 ).arg( 1 )
315 .arg( nNumberOfStrips ) );
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]" )
330 pController->toggleStripIsMuted( nStrip );
331 bMessageProcessed =
true;
334 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
335 .arg( nStrip + 1 ).arg( 1 )
336 .arg( nNumberOfStrips ) );
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]" )
351 pController->toggleStripIsSoloed( nStrip );
352 bMessageProcessed =
true;
355 ERRORLOG( QString(
"Provided strip number [%1] out of bound [%2,%3]" )
356 .arg( nStrip + 1 ).arg( 1 )
357 .arg( nNumberOfStrips ) );
361 if ( ! bMessageProcessed ) {
362 ERRORLOG(
"No matching handler found" );
378 if ( m_pPreferences->m_nOscTemporaryPort != -1 ) {
379 nPort = m_pPreferences->m_nOscTemporaryPort;
381 nPort = m_pPreferences->getOscServerPort();
389 delete m_pServerThread;
393 m_pServerThread = new lo::ServerThread( nullptr );
395 const int nTmpPort = m_pServerThread->port();
397 ERRORLOG( QString(
"Could not start OSC server on port %1, using port %2 instead.")
398 .arg( nPort ).arg( nTmpPort ) );
400 m_pPreferences->m_nOscTemporaryPort = nTmpPort;
402 H2Core::EventQueue::get_instance()->push_event(
403 H2Core::EVENT_ERROR, H2Core::Hydrogen::OSC_CANNOT_CONNECT_TO_PORT );
407 m_pServerThread =
nullptr;
414 lo_address_free( *it );
434 INFOLOG(
"processing message" );
435 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PLAY");
444 INFOLOG(
"processing message" );
445 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PLAY/STOP_TOGGLE");
454 INFOLOG(
"processing message" );
455 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PLAY/PAUSE_TOGGLE");
464 INFOLOG(
"processing message" );
465 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"STOP");
474 INFOLOG(
"processing message" );
475 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PAUSE");
484 INFOLOG(
"processing message" );
485 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"RECORD_READY");
494 INFOLOG(
"processing message" );
495 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"RECORD/STROBE_TOGGLE");
504 INFOLOG(
"processing message" );
505 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"RECORD_STROBE");
514 INFOLOG(
"processing message" );
515 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"RECORD_EXIT");
524 INFOLOG(
"processing message" );
525 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"MUTE");
534 INFOLOG(
"processing message" );
535 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"UNMUTE");
544 INFOLOG(
"processing message" );
545 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"MUTE_TOGGLE");
554 INFOLOG(
"processing message" );
555 std::shared_ptr<Action> pAction = std::make_shared<Action>(
">>_NEXT_BAR");
564 INFOLOG(
"processing message" );
565 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"<<_PREVIOUS_BAR");
574 INFOLOG(
"processing message" );
576 auto pAudioEngine = pHydrogen->getAudioEngine();
578 float fNewBpm = argv[0]->f;
579 fNewBpm = std::clamp( fNewBpm,
static_cast<float>(
MIN_BPM),
583 pAudioEngine->setNextBpm( fNewBpm );
584 pAudioEngine->unlock();
586 pHydrogen->getSong()->setBpm( fNewBpm );
588 pHydrogen->setIsModified(
true );
595 INFOLOG(
"processing message" );
596 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"BPM_INCR");
599 pAction->setParameter1( QString::number( argv[0]->f,
'f', 0 ));
607 INFOLOG(
"processing message" );
608 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"BPM_DECR");
611 pAction->setParameter1( QString::number( argv[0]->f,
'f', 0 ));
619 INFOLOG(
"processing message" );
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 ));
640 INFOLOG(
"processing message" );
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 );
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 ) );
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 ) );
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 ) );
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 );
708 INFOLOG(
"processing message" );
711 setInstrumentPitch(
static_cast<int>( argv[0]->f ), argv[1]->f );
716 INFOLOG(
"processing message" );
717 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"BEATCOUNTER");
726 INFOLOG(
"processing message" );
727 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"TAP_TEMPO");
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 ) );
748 INFOLOG(
"processing message" );
749 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PLAYLIST_NEXT_SONG");
758 INFOLOG(
"processing message" );
759 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"PLAYLIST_PREV_SONG");
768 INFOLOG(
"processing message" );
769 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"TOGGLE_METRONOME");
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 ) );
790 INFOLOG(
"processing message" );
791 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"UNDO_ACTION");
800 INFOLOG(
"processing message" );
801 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"REDO_ACTION");
812 INFOLOG(
"processing message" );
814 auto pController = pHydrogen->getCoreActionController();
815 pController->newSong( QString::fromUtf8( &argv[0]->s ) );
819 INFOLOG(
"processing message" );
821 auto pController = pHydrogen->getCoreActionController();
822 pController->openSong( QString::fromUtf8( &argv[0]->s ) );
826 INFOLOG(
"processing message" );
828 if ( pHydrogen->getSong() ==
nullptr ) {
833 auto pController = pHydrogen->getCoreActionController();
834 pController->saveSong();
838 INFOLOG(
"processing message" );
840 if ( pHydrogen->getSong() ==
nullptr ) {
845 auto pController = pHydrogen->getCoreActionController();
846 pController->saveSongAs( QString::fromUtf8( &argv[0]->s ) );
850 INFOLOG(
"processing message" );
852 if ( pHydrogen->getSong() ==
nullptr ) {
857 auto pController = pHydrogen->getCoreActionController();
858 pController->savePreferences();
862 INFOLOG(
"processing message" );
864 auto pController = pHydrogen->getCoreActionController();
871 INFOLOG(
"processing message" );
873 if ( pHydrogen->getSong() ==
nullptr ) {
878 auto pController = pHydrogen->getCoreActionController();
880 if ( argv[0]->f != 0 ) {
881 pController->activateTimeline(
true );
883 pController->activateTimeline(
false );
888 INFOLOG(
"processing message" );
890 if ( pHydrogen->getSong() ==
nullptr ) {
895 auto pController = pHydrogen->getCoreActionController();
896 pController->addTempoMarker(
static_cast<int>(std::round( argv[0]->f )),
901 INFOLOG(
"processing message" );
903 if ( pHydrogen->getSong() ==
nullptr ) {
908 auto pController = pHydrogen->getCoreActionController();
909 pController->deleteTempoMarker(
static_cast<int>( std::round( argv[0]->f ) ) );
913 INFOLOG(
"processing message" );
915 if ( pHydrogen->getSong() ==
nullptr ) {
920 auto pController = pHydrogen->getCoreActionController();
922 if ( argv[0]->f != 0 ) {
923 pController->activateJackTransport(
true );
925 pController->activateJackTransport(
false );
930 INFOLOG(
"processing message" );
932 if ( pHydrogen->getSong() ==
nullptr ) {
937 auto pController = pHydrogen->getCoreActionController();
938 if ( argv[0]->f != 0 ) {
939 pController->activateJackTimebaseControl(
true );
941 pController->activateJackTimebaseControl(
false );
946 INFOLOG(
"processing message" );
948 if ( pHydrogen->getSong() ==
nullptr ) {
953 auto pController = pHydrogen->getCoreActionController();
954 if ( argv[0]->f != 0 ) {
955 pController->activateSongMode(
true );
957 pController->activateSongMode(
false );
962 INFOLOG(
"processing message" );
964 if ( pHydrogen->getSong() ==
nullptr ) {
969 auto pController = pHydrogen->getCoreActionController();
970 if ( argv[0]->f != 0 ) {
971 pController->activateLoopMode(
true );
973 pController->activateLoopMode(
false );
978 INFOLOG(
"processing message" );
980 if ( pHydrogen->getSong() ==
nullptr ) {
985 pHydrogen->getCoreActionController()->locateToColumn(
static_cast<int>(std::round( argv[0]->f ) ) );
989 INFOLOG(
"processing message" );
991 if ( pHydrogen->getSong() ==
nullptr ) {
996 auto pController = pHydrogen->getCoreActionController();
997 pController->newPattern( QString::fromUtf8( &argv[0]->s ) );
1001 INFOLOG(
"processing message" );
1003 if ( pHydrogen->getSong() ==
nullptr ) {
1008 auto pController = pHydrogen->getCoreActionController();
1009 pController->openPattern( QString::fromUtf8( &argv[0]->s ) );
1013 INFOLOG(
"processing message" );
1015 if ( pHydrogen->getSong() ==
nullptr ) {
1020 auto pController = pHydrogen->getCoreActionController();
1021 pController->removePattern(
static_cast<int>(std::round( argv[0]->f )) );
1026 INFOLOG(
"processing message" );
1028 const int nInstr = pHydrogen->getSelectedInstrumentNumber();
1029 if ( nInstr == -1 ) {
1034 pHydrogen->getCoreActionController()->clearInstrumentInPattern( nInstr );
1039 INFOLOG(
"processing message" );
1046 INFOLOG(
"processing message" );
1047 std::shared_ptr<Action> pAction = std::make_shared<Action>(
"CLEAR_PATTERN" );
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]." )
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 ) );
1066 else if ( fVelocity > 1.0 ) {
1067 WARNINGLOG( QString(
"Provided velocity [%1] out of bound. Using maximum value [1.0] instead." )
1068 .arg( fVelocity ) );
1072 INFOLOG( QString(
"processing message with note: [%1] and velocity: [%2]" )
1073 .arg( nNote ).arg( fVelocity ) );
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]." )
1088 INFOLOG( QString(
"processing message with note: [%1]" ).arg( nNote ) );
1095 INFOLOG(
"processing message" );
1097 if ( pHydrogen->getSong() ==
nullptr ) {
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 )) );
1108 INFOLOG(
"processing message" );
1110 if ( pHydrogen->getSong() ==
nullptr ) {
1115 auto pController = pHydrogen->getCoreActionController();
1117 bool bConditionalLoad =
true;
1119 bConditionalLoad = argv[1]->f == 0 ? false :
true;
1122 pController->setDrumkit( QString::fromUtf8( &argv[0]->s ),
1127 INFOLOG(
"processing message" );
1131 QString sNewPath =
"";
1133 sNewPath = QString::fromUtf8( &argv[1]->s );
1141 INFOLOG(
"processing message" );
1143 bool bValidateLegacyKits =
false;
1145 bValidateLegacyKits = argv[1]->f == 0 ? false :
true;
1150 bValidateLegacyKits );
1154 INFOLOG(
"processing message" );
1158 QString sTargetDir =
"";
1160 sTargetDir = QString::fromUtf8( &argv[1]->s );
1163 pController->
extractDrumkit( QString::fromUtf8( &argv[0]->s ), sTargetDir );
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 ) );
1175 return portEqual && hostEqual && protoEqual;
1181 INFOLOG( QString(
"Outgoing OSC broadcast message %1" ).arg( msgText ));
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));
1189 lo_send_message(clientAddress, msgText, message);
1204 if( pAction->getType() ==
"MASTER_VOLUME_ABSOLUTE"){
1206 float fValue = pAction->getValue().toFloat(&ok);
1208 lo_message reply = lo_message_new();
1209 lo_message_add_float( reply, fValue );
1213 lo_message_free( reply );
1216 if( pAction->getType() ==
"STRIP_VOLUME_ABSOLUTE"){
1218 float fValue = pAction->getValue().toFloat(&ok);
1220 lo_message reply = lo_message_new();
1221 lo_message_add_float( reply, fValue );
1223 QByteArray ba = QString(
"/Hydrogen/STRIP_VOLUME_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1224 const char *c_str2 = ba.data();
1228 lo_message_free( reply );
1231 if( pAction->getType() ==
"TOGGLE_METRONOME"){
1233 float param1 = pAction->getParameter1().toFloat(&ok);
1235 lo_message reply = lo_message_new();
1236 lo_message_add_float(reply, param1);
1240 lo_message_free( reply );
1243 if( pAction->getType() ==
"MUTE_TOGGLE"){
1245 float param1 = pAction->getParameter1().toFloat(&ok);
1247 lo_message reply = lo_message_new();
1248 lo_message_add_float(reply, param1);
1252 lo_message_free( reply );
1255 if( pAction->getType() ==
"STRIP_MUTE_TOGGLE"){
1257 float fValue = pAction->getValue().toFloat(&ok);
1259 lo_message reply = lo_message_new();
1260 lo_message_add_float( reply, fValue );
1262 QByteArray ba = QString(
"/Hydrogen/STRIP_MUTE_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1263 const char *c_str2 = ba.data();
1267 lo_message_free( reply );
1270 if( pAction->getType() ==
"STRIP_SOLO_TOGGLE"){
1272 float fValue = pAction->getValue().toFloat(&ok);
1274 lo_message reply = lo_message_new();
1275 lo_message_add_float( reply, fValue );
1277 QByteArray ba = QString(
"/Hydrogen/STRIP_SOLO_TOGGLE/%1").arg(pAction->getParameter1()).toLatin1();
1278 const char *c_str2 = ba.data();
1282 lo_message_free( reply );
1285 if( pAction->getType() ==
"PAN_ABSOLUTE"){
1287 float fValue = pAction->getValue().toFloat(&ok);
1289 lo_message reply = lo_message_new();
1290 lo_message_add_float( reply, fValue );
1292 QByteArray ba = QString(
"/Hydrogen/PAN_ABSOLUTE/%1").arg(pAction->getParameter1()).toLatin1();
1293 const char *c_str2 = ba.data();
1297 lo_message_free( reply );
1300 if( pAction->getType() ==
"PAN_ABSOLUTE_SYM"){
1302 float fValue = pAction->getValue().toFloat(&ok);
1304 lo_message reply = lo_message_new();
1305 lo_message_add_float( reply, fValue );
1307 QByteArray ba = QString(
"/Hydrogen/PAN_ABSOLUTE_SYM/%1").arg(pAction->getParameter1()).toLatin1();
1308 const char *c_str2 = ba.data();
1312 lo_message_free( reply );
1319 ERRORLOG(
"Failed to initialize OSC server. No valid server thread.");
1329 lo_address address = lo_message_get_source(msg);
1331 bool AddressRegistered =
false;
1334 AddressRegistered =
true;
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 ) );
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 ) ) );
1454 m_pServerThread->add_method(
"/Hydrogen/CLEAR_SELECTED_INSTRUMENT",
"",
1456 m_pServerThread->add_method(
"/Hydrogen/CLEAR_SELECTED_INSTRUMENT",
"f",
1483 ERRORLOG(
"Failed to start OSC server. No valid server thread.");
1502 INFOLOG( QString(
"Osc server started. Listening on port %1" )
1503 .arg( nOscPortUsed ) );
1510 ERRORLOG(
"Failed to stop OSC server. No valid server thread.");
1515 INFOLOG(QString(
"Osc server stopped" ));
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
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)
bool initExternalControlInterfaces()
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
CoreActionController * getCoreActionController() const
static constexpr int instrumentOffset
When recording notes using MIDI NOTE_ON events this offset will be applied to the provided pitch in o...
Manager for User Preferences File (singleton)
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
bool getOscFeedbackEnabled()
The MidiActionManager cares for the execution of MidiActions.
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.
OSC Server implementation.
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.
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.
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.
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.
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.
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.
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.