123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- //*****************************************//
- // 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 <iostream>
- #include <cstdlib>
- #include "RtMidi.h"
- // Platform-dependent sleep routines.
- #if defined(WIN32)
- #include <windows.h>
- #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
- #else // Unix variants
- #include <unistd.h>
- #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<unsigned int*>(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 <<std::endl;
- *clock_count = 0;
- }
- }
- else
- *clock_count = 0;
- }
- int clock_in()
- {
- RtMidiIn *midiin = 0;
- unsigned int clock_count = 0;
- try {
- // RtMidiIn constructor
- midiin = new RtMidiIn();
- // Call function to select port.
- if ( chooseInputPort( midiin ) == false ) goto cleanup;
- // Set our callback function. This should be done immediately after
- // opening the port to avoid having incoming messages written to the
- // queue instead of sent to the callback function.
- midiin->setCallback( &mycallback, &clock_count );
- // Don't ignore sysex, timing, or active sensing messages.
- midiin->ignoreTypes( false, false, false );
- std::cout << "\nReading MIDI input ... press <enter> 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<unsigned char> 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<typename RT>
- 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; i<nPorts; i++ ) {
- portName = rtmidi->getPortName(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<RtMidiIn>( rtmidi, "input" );
- }
- bool chooseOutputPort( RtMidiOut *rtmidi )
- {
- return choosePort<RtMidiOut>( rtmidi, "output" );
- }
|