1 // playsmf.cpp
2 //
3 // Simple program to test the MidiFileIn class by reading and playing
4 // a single track from a given Standard MIDI file.
5 //
6 // by Gary Scavone, 2003.
7 
8 #include "MidiFileIn.h"
9 #include "RtMidi.h"
10 #include <signal.h>
11 #include <cstdlib>
12 
13 bool done = false;
finish(int ignore)14 static void finish(int ignore){ done = true; }
15 
16 using namespace stk;
17 
usage(void)18 void usage(void) {
19   // Error function in case of incorrect command-line
20   // argument specifications.
21   std::cout << "\nusage: playsmf file track <port>\n";
22   std::cout << "   where file = a standard MIDI file,\n";
23   std::cout << "   track = the track to play (0 = 1st track),\n";
24   std::cout << "   and an optional port integer identifier can be specified\n";
25   std::cout << "   (default = 0) or a value of -1 to use a virtual MIDI output port.\n\n";
26   exit( 0 );
27 }
28 
main(int argc,char * argv[])29 int main( int argc, char *argv[] )
30 {
31   RtMidiOut *midiout = 0;
32 
33   if ( argc < 3 || argc > 4 ) usage();
34 
35   // Attempt to instantiate MIDI output class.
36   try {
37     midiout = new RtMidiOut();
38   }
39   catch ( RtMidiError& error ) {
40     error.printMessage();
41     exit(0);
42   }
43 
44   // Check command-line arguments.
45   int port = 0;
46   if ( argc == 4 ) port = atoi( argv[3] );
47   if ( port == -1 ) {
48     try {
49       midiout->openVirtualPort();
50     }
51     catch ( RtMidiError& error ) {
52       error.printMessage();
53       goto cleanup;
54     }
55     std::cout << "\nVirtual port open.\n\n";
56   }
57   else {
58     if ( midiout->getPortCount() < 1 ) {
59       std::cout << "\nThere are no MIDI output destinations available!\n\n";
60       goto cleanup;
61     }
62     try {
63       midiout->openPort( port );
64     }
65     catch ( RtMidiError& error ) {
66       error.printMessage();
67       goto cleanup;
68     }
69   }
70 
71   // Install an interrupt handler function.  Type "ctrl-c" to quit the
72   // program.
73   (void) signal( SIGINT, finish );
74 
75   try {
76     MidiFileIn midiFile( argv[1] );
77 
78     // Print a little information about the file.
79     std::cout << "\nThe MIDI file (" << argv[1] << ") information:\n";
80     std::cout << "  - format = " << midiFile.getFileFormat() << "\n";
81     std::cout << "  - tracks = " << midiFile.getNumberOfTracks() << "\n";
82     std::cout << "  - seconds / ticks = " << midiFile.getTickSeconds() << "\n";
83 
84     unsigned int track = (unsigned int) atoi( argv[2] );
85     if ( midiFile.getNumberOfTracks() <= track ) {
86       std::cout << "\nInvalid track number ... playing track 0.\n";
87       track = 0;
88     }
89 
90     std::cout << "\nPress <enter> to start reading/playing.\n";
91     char input;
92     std::cin.get(input);
93 
94     std::vector<unsigned char> event;
95     unsigned long ticks = midiFile.getNextMidiEvent( &event, track );
96     while ( !done && event.size() ) {
97 
98       // Pause for the MIDI event delta time.
99       Stk::sleep( (unsigned long) (ticks * midiFile.getTickSeconds() * 1000 ) );
100 
101       midiout->sendMessage( &event );
102 
103       // Get a new event.
104       ticks = midiFile.getNextMidiEvent( &event, track );
105     }
106 
107     // Send a "all notes off" to the synthesizer.
108     event.clear();
109     event.push_back( 0xb0 );
110     event.push_back( 0x7b );
111     event.push_back( 0x0 );
112     midiout->sendMessage( &event );
113   }
114   catch ( StkError & ) {
115     // You might want to do something more useful here.
116     std::cout << "\nAborting program!\n";
117     goto cleanup;
118   }
119 
120  cleanup:
121   delete midiout;
122 
123   return 0;
124 }
125