//*****************************************// // midiclock.cpp // // Simple program to test MIDI clock sync. Run midiclock_in in one // console and midiclock_out in the other, make sure to choose // options that connect the clocks between programs on your platform. // // (C)2016 Refer to README.md in this archive for copyright. // //*****************************************// #include #include #include "RtMidi.h" // Platform-dependent sleep routines. #if defined(WIN32) #include #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) #else // Unix variants #include #define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) ) #endif // These functions should be embedded in a try/catch block in case of // an exception. It offers the user a choice of MIDI ports to open. // It returns false if there are no ports available. bool chooseInputPort( RtMidiIn *rtmidi ); bool chooseOutputPort( RtMidiOut *rtmidi ); void mycallback( double deltatime, std::vector< unsigned char > *message, void *user ) { unsigned int *clock_count = reinterpret_cast(user); // Ignore longer messages if (message->size() != 1) return; unsigned int msg = message->at(0); if (msg == 0xFA) std::cout << "START received" << std::endl; if (msg == 0xFB) std::cout << "CONTINUE received" << std::endl; if (msg == 0xFC) std::cout << "STOP received" << std::endl; if (msg == 0xF8) { if (++*clock_count == 24) { double bpm = 60.0 / 24.0 / deltatime; std::cout << "One beat, estimated BPM = " << bpm <setCallback( &mycallback, &clock_count ); // Don't ignore sysex, timing, or active sensing messages. midiin->ignoreTypes( false, false, false ); std::cout << "\nReading MIDI input ... press to quit.\n"; char input; std::cin.get(input); } catch ( RtMidiError &error ) { error.printMessage(); } cleanup: delete midiin; return 0; } int clock_out() { RtMidiOut *midiout = 0; std::vector message; int sleep_ms = 0, k = 0, j = 0; // RtMidiOut constructor try { midiout = new RtMidiOut(); } catch ( RtMidiError &error ) { error.printMessage(); exit( EXIT_FAILURE ); } // Call function to select port. try { if ( chooseOutputPort( midiout ) == false ) goto cleanup; } catch ( RtMidiError &error ) { error.printMessage(); goto cleanup; } // Period in ms = 100 BPM // 100*24 ticks / 1 minute, so (60*1000) / (100*24) = 25 ms / tick sleep_ms = 25; std::cout << "Generating clock at " << (60.0 / 24.0 / sleep_ms * 1000.0) << " BPM." << std::endl; // Send out a series of MIDI clock messages. // MIDI start message.clear(); message.push_back( 0xFA ); midiout->sendMessage( &message ); std::cout << "MIDI start" << std::endl; for (j=0; j < 8; j++) { if (j > 0) { // MIDI continue message.clear(); message.push_back( 0xFB ); midiout->sendMessage( &message ); std::cout << "MIDI continue" << std::endl; } for (k=0; k < 96; k++) { // MIDI clock message.clear(); message.push_back( 0xF8 ); midiout->sendMessage( &message ); if (k % 24 == 0) std::cout << "MIDI clock (one beat)" << std::endl; SLEEP( sleep_ms ); } // MIDI stop message.clear(); message.push_back( 0xFC ); midiout->sendMessage( &message ); std::cout << "MIDI stop" << std::endl; SLEEP( 500 ); } // MIDI stop message.clear(); message.push_back( 0xFC ); midiout->sendMessage( &message ); std::cout << "MIDI stop" << std::endl; SLEEP( 500 ); std::cout << "Done!" << std::endl; // Clean up cleanup: delete midiout; return 0; } int main( int, const char *argv[] ) { std::string prog(argv[0]); if (prog.find("midiclock_in") != prog.npos) { clock_in(); } else if (prog.find("midiclock_out") != prog.npos) { clock_out(); } else { std::cout << "Don't know what to do as " << prog << std::endl; } return 0; } template bool choosePort( RT *rtmidi, const char *dir ) { std::string portName; unsigned int i = 0, nPorts = rtmidi->getPortCount(); if ( nPorts == 0 ) { std::cout << "No " << dir << " ports available!" << std::endl; return false; } if ( nPorts == 1 ) { std::cout << "\nOpening " << rtmidi->getPortName() << std::endl; } else { for ( i=0; igetPortName(i); std::cout << " " << dir << " port #" << i << ": " << portName << '\n'; } do { std::cout << "\nChoose a port number: "; std::cin >> i; } while ( i >= nPorts ); } std::cout << "\n"; rtmidi->openPort( i ); return true; } bool chooseInputPort( RtMidiIn *rtmidi ) { return choosePort( rtmidi, "input" ); } bool chooseOutputPort( RtMidiOut *rtmidi ) { return choosePort( rtmidi, "output" ); }