Need help with compiling RtMidi program

First off, my introduction. I will post it here, so that you know where I am coming from. Hopefully this is the last time I will have to tell this sorry story and I can finally get on with my life.
[Introduction]
About twenty years ago I graduated high school and went off to college. The college that offered me the most money was small, and only offered Associates level degrees. Being from a small town (2000k then, ~700 in the last census) I didn't know much about the world. Ideas like "you only need one Associates degree," So I stayed at the college until I had two Associates degrees. Then I transferred to an actual university in another town. The advisor they assigned me actually fell out of his chair when he saw my transcript. I had 128 credit hours of Associates-level classes. I attended that university for a year. I got burnt out. It happens to the best of us at some point. But, just to be clear, I do not consider myself the best of any collective 'us'. Most of the time, I consider myself closer to the other end of the spectrum. I went through several stages of Darkness, ending up angry and terrified of people. This lasted for about 15 years. I lost most of my skills. (If you don't use them, you lose them.) I sat in front of the television, consuming mindless Entertainment. About 2013, I discovered YouTube. Then, I finally started meditating and asking a higher power if there was a way out. That was about three years ago. I am now attempting to reclaim my life. I sing in the church choir, I set up tables and chairs for their weekly community dinner. I'm around people. I can't talk to all of them yet, but I made it this far. Today, I'm actually going to seek gainful employment. I haven't worked since I burnt out. I am learning to program again. From the beginning. I bought Stroustrup's PPP book, and am working through it. I'm only on Chapter 2 at the time of this writing, but I'm not giving up this time. There's too much at stake.
[/Introduction]
And now on to my actual problem. I think this is probably due to my lack of CLI experience. My arguments are probably in the wrong order.

1
2
3
4
5
  michael@caitlyn sing $ g++ -Wall -D__LINUX_ALSA__ -o midiout midiout.cpp -lasound -lpthread
/tmp/ccCbm3tY.o: In function `main':
midiout.cpp:(.text+0x49): undefined reference to `RtMidiOut::RtMidiOut(RtMidi::Api, std::string const&)'
collect2: error: ld returned 1 exit status


I create a Notes.txt file for each project I plan to work on (some day). This particular project's Notes file says:

1
2
3
4
5
6
7
8
michael@caitlyn sing $ cat Notes.txt 
Program should provide solfedge (Do-Re-Mi) on a scale starting at a particular
note.  It should then select one note on that scale.  This note will be
skipped.  On each run through the scale, the skip note will be skipped.   

Ex:  Do-Re-Me-Fa-So-La-Ti-Do
     The skip note is Ti, so it would be:
     Do-Re-Me-Fa-So-L
     Do----La-So-Fa-Me-Re-Do.

The scale should run forward and backward.
The note should be outputted through the MIDI interface.

michael@caitlyn sing $ 


I have not altered midiout.cpp. I copied it from https://www.music.mcgill.ca/~gary/rtmidi/index.html#download. I built it in /home/michael with ./configure --prefix=/opt (I've been told on numerous occasions that non-Slackware code belongs in /opt). Then I logged into root and ran make install. Please help me figure this out, and thank you in advance for any help you offer. Thank you also for your patience with me, and all my rambling.
closed account (SECMoG1T)
we need to see the code you've written, so we can help you debug.
closed account (SECMoG1T)
i have also noticed that you din't include the RtMidi.cpp in your compilation.

michael@caitlyn sing $ g++ -Wall -D__LINUX_ALSA__ -o midiout midiout.cpp -lasound -lpthread


should be

michael@caitlyn sing $ g++ -Wall -D__LINUX_ALSA__ -o midiout midiout.cpp RtMidi.cpp -lasound -lpthread


assuming that {midiout.cpp , RtMidi.cpp, RtMidi.h} exist in the same dir.
Last edited on
OK. I wasn't aware that I would need RtMidi.cpp. But I've linked it in and rebuilt the program. It compiles and links now. No sound though when I run it.
closed account (SECMoG1T)
where is your code?
1
2
3
4
5
6
7
8
9
michael@caitlyn sing $ ls -l
total 120
-rw-r--r-- 1 michael michael    460 Nov 29 12:08 Notes.txt
lrwxrwxrwx 1 michael michael     37 Nov 29 20:57 RtMidi.cpp -> /home/michael/rtmidi-3.0.0/RtMidi.cpp
lrwxrwxrwx 1 michael michael     35 Nov 29 09:48 RtMidi.h -> /home/michael/rtmidi-3.0.0/RtMidi.h
-rwxr-xr-x 1 michael michael 108024 Nov 29 20:58 midiout
-rw-r--r-- 1 michael michael   1351 Nov 29 11:20 midiout.cpp
-rw-r--r-- 1 michael michael   1382 Nov 29 09:25 midiprobe.cpp
lrwxrwxrwx 1 michael michael     33 Nov 29 09:54 tests -> /home/michael/rtmidi-3.0.0/tests/


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
michael@caitlyn sing $ cat midiout.cpp
// midiout.cpp

#include <iostream>
#include <cstdlib>
#include "RtMidi.h"

// Platform-dependent sleep routines.
#if defined(__WINDOWS_MM__)
  #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

int main()
{
  RtMidiOut *midiout = new RtMidiOut();
  std::vector<unsigned char> message;
  // Check available ports.
  unsigned int nPorts = midiout->getPortCount();
  if ( nPorts == 0 ) {
    std::cout << "No ports available!\n";
    goto cleanup;
  }
  // Open first available port.
  midiout->openPort( 0 );
  // Send out a series of MIDI messages.
  // Program change: 192, 5
  message.push_back( 192 );
  message.push_back( 5 );
  midiout->sendMessage( &message );
  // Control Change: 176, 7, 100 (volume)
  message[0] = 176;
  message[1] = 7;
  message.push_back( 100 );
  midiout->sendMessage( &message );
  // Note On: 144, 64, 90
  message[0] = 144;
  message[1] = 64;
  message[2] = 90;
  midiout->sendMessage( &message );
  SLEEP( 500 ); // Platform-dependent ... see example in tests directory.
  // Note Off: 128, 64, 40
  message[0] = 128;
  message[1] = 64;
  message[2] = 40;
  midiout->sendMessage( &message );
  // Clean up
 cleanup:
  delete midiout;
  return 0;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
michael@caitlyn sing $ cat midiprobe.cpp 
// midiprobe.cpp
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
int main()
{
  RtMidiIn  *midiin = 0;
  RtMidiOut *midiout = 0;
  // RtMidiIn constructor
  try {
    midiin = new RtMidiIn();
  }
  catch ( RtMidiError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }
  // Check inputs.
  unsigned int nPorts = midiin->getPortCount();
  std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
  std::string portName;
  for ( unsigned int i=0; i<nPorts; i++ ) {
    try {
      portName = midiin->getPortName(i);
    }
    catch ( RtMidiError &error ) {
      error.printMessage();
      goto cleanup;
    }
    std::cout << "  Input Port #" << i+1 << ": " << portName << '\n';
  }
  // RtMidiOut constructor
  try {
    midiout = new RtMidiOut();
  }
  catch ( RtMidiError &error ) {
    error.printMessage();
    exit( EXIT_FAILURE );
  }
  // Check outputs.
  nPorts = midiout->getPortCount();
  std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
  for ( unsigned int i=0; i<nPorts; i++ ) {
    try {
      portName = midiout->getPortName(i);
    }
    catch (RtMidiError &error) {
      error.printMessage();
      goto cleanup;
    }
    std::cout << "  Output Port #" << i+1 << ": " << portName << '\n';
  }
  std::cout << '\n';
  // Clean up
 cleanup:
  delete midiin;
  delete midiout;
  return 0;
}

michael@caitlyn sing $ 


Midiout.cpp and midiprobe.cpp copied from example at https://www.music.mcgill.ca/~gary/rtmidi/index.html
closed account (SECMoG1T)
please run this file "midiprobe.cpp" do you get any midi out channels?

i have tested your code on windows and both files works fine, the sound plays ok although i had to setup virtual midi ports for it to work.
closed account (SECMoG1T)
to confirm it works out i have created this cpp that run random notes , test see if you get anything.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121


#include <vector>
#include "RtMidi.h"
#include <random>
#include <ctime>
#include <thread>
#include <chrono>
#include <memory>


    enum VALUE_BOUND{MIN = 0, MAX = 127};/// settings apart from channel select use this range of values

    enum CH_CONSTS{ NOTE_ON        = 0x90,
                    NOTE_OFF       = 0x80,
                    KEY_AFTERTOUCH = 0xA0,
                    CONTROL_CHANGE = 0xB0,
                    PROG_CHANGE    = 0xC0,
                    CH_AFTERTOUCH  = 0xD0,
                    PITCH_BEND     = 0xE0
                  };  ///each seting above have its own channel prefix


int random_number(int lower,int upper)
{
    static std::mt19937 _mt(std::time(nullptr));
    static std::uniform_int_distribution<int> _uint_dstr(lower,upper);

    return _uint_dstr(_mt);
}

void sleep()
{
   std::this_thread::sleep_for(std::chrono::milliseconds(300));
}

template<typename RtMode>
std::shared_ptr<RtMode> init_mode()
{
        auto rt_mode_ptr   = std::make_shared<RtMode>();
        auto ports = rt_mode_ptr->getPortCount();

        if(ports)
            return rt_mode_ptr;

        return nullptr;///no ports available
}

template<typename T>
bool open_port(std::shared_ptr<T>& modeptr,unsigned int port_num)
{
    if(port_num < modeptr->getPortCount())
     {
         modeptr->openPort(port_num);
         return true;
     }

     return false;
}

template<typename RtType>
struct RtMode
{
    RtMode(std::shared_ptr<RtType>& ptr):Rt_ptr(ptr){}

    std::shared_ptr<RtType> Rt_ptr;
    void send(const std::vector<unsigned char>& mssg){ Rt_ptr->sendMessage(&mssg);}
};

int main()
{
    constexpr int OUTPUT_PORT = 0,REL_VEL = 90,MY_CHANNEL=0,VOLUME_SELECT=7;

    std::vector<unsigned char> message{0,0,0};

    ///am using output only
    auto Rt_out_ptr = init_mode<RtMidiOut>();

    if(Rt_out_ptr && open_port(Rt_out_ptr,OUTPUT_PORT))///if there are ports and we manage to open our desired port.
    {
        RtMode<RtMidiOut> out_handle(Rt_out_ptr);

        ///select electric guitar(clean)
        message[0]=(CH_CONSTS::PROG_CHANGE + MY_CHANNEL);
        message[1]=27;

        out_handle.send(message);

        ///set volume to 120
        message[0]=(CH_CONSTS::CONTROL_CHANGE+ MY_CHANNEL);
        message[1]= (VOLUME_SELECT);
        message[2]= 120;

        out_handle.send(message);

        ///generate random notes using an electric guitar
        int key = 0;
        message[2]=(REL_VEL);///key release velocity wont change in the loop
        for(int i = 0; i < 100; i++)
        {
            key = random_number(VALUE_BOUND::MIN,VALUE_BOUND::MAX);///get a random key 0 - 127

            ///turn note on
            message[0]=(CH_CONSTS::NOTE_ON+MY_CHANNEL);
            message[1]=(key);

            out_handle.send(message);

            sleep();

            ///turn them off
            message[0]=(CH_CONSTS::NOTE_OFF+MY_CHANNEL);
            out_handle.send(message);
        }
    }

    else
        std::cout<<"no ports available";
}

Last edited on
1
2
3
4
michael@caitlyn sing $ g++ -Wall -D__LINUX_ALSA__ -o test test.cpp  RtMidi.cpp -lasound -lpthreadmichael@caitlyn sing $ ./test

MidiOutAlsa::sendMessage: event parsing error!
closed account (SECMoG1T)
ooh i see, the code is running perfectly on win, can i ask you which synthesizer are you connecting your port to?

i used the following specification to send the mssgs

https://openmidiproject.osdn.jp/documentations_en.html

I don't know anything about this stuff. AFAIK, I'm not hooking it up to any synthesizer. Do I need to, and if so, how do I do that?
closed account (SECMoG1T)
try this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <vector>
#include "RtMidi.h"
#include <random>
#include <ctime>
#include <thread>
#include <chrono>
#include <memory>


    enum VALUE_BOUND{MIN = 0, MAX = 127};/// settings apart from channel select use this range of values

    enum CH_CONSTS{ NOTE_ON        = 0x90,
                    NOTE_OFF       = 0x80,
                    KEY_AFTERTOUCH = 0xA0,
                    CONTROL_CHANGE = 0xB0,
                    PROG_CHANGE    = 0xC0,
                    CH_AFTERTOUCH  = 0xD0,
                    PITCH_BEND     = 0xE0
                  };  ///each seting above have its own channel prefix


int random_number(int lower,int upper)
{
    static std::mt19937 _mt(std::time(nullptr));
    static std::uniform_int_distribution<int> _uint_dstr(lower,upper);

    return _uint_dstr(_mt);
}

void sleep()
{
   std::this_thread::sleep_for(std::chrono::milliseconds(300));
}

template<typename RtMode>
std::shared_ptr<RtMode> init_mode()
{
        auto rt_mode_ptr   = std::make_shared<RtMode>();
        auto ports = rt_mode_ptr->getPortCount();

        if(ports)
            return rt_mode_ptr;

        return nullptr;///no ports available
}

template<typename T>
bool open_port(std::shared_ptr<T>& modeptr,unsigned int port_num)
{
    if(port_num < modeptr->getPortCount())
     {
         modeptr->openPort(port_num);
         return true;
     }

     return false;
}

template<typename RtType>
struct RtMode
{
    RtMode(std::shared_ptr<RtType>& ptr):Rt_ptr(ptr){}

    std::shared_ptr<RtType> Rt_ptr;
    void send(const std::vector<unsigned char>& mssg){ Rt_ptr->sendMessage(&mssg);}
};

int main()
{
    constexpr int OUTPUT_PORT = 0,REL_VEL = 90,MY_CHANNEL=0,VOLUME_SELECT=7;

    std::vector<unsigned char> message{0,0,0};

    ///am using output only
    auto Rt_out_ptr = init_mode<RtMidiOut>();

    if(Rt_out_ptr && open_port(Rt_out_ptr,OUTPUT_PORT))///if there are ports and we manage to open our desired port.
    {
        RtMode<RtMidiOut> out_handle(Rt_out_ptr);

        ///select electric guitar(clean)
        message[0]=(CH_CONSTS::PROG_CHANGE + MY_CHANNEL);
        message[1]=27;

        out_handle.send(message);

        ///set volume to 120
        message[0]=(CH_CONSTS::CONTROL_CHANGE+ MY_CHANNEL);
        message[1]= (VOLUME_SELECT);
        message[2]= 120;

        out_handle.send(message);

        ///generate random notes using an electric guitar
        int key = 0;

        for(int i = 0; i < 100; i++)
        {
            key = random_number(VALUE_BOUND::MIN,VALUE_BOUND::MAX);///get a random key 0 - 127

            ///turn note on
            message[0]=(CH_CONSTS::NOTE_ON+MY_CHANNEL);
            message[1]=(key);
            message[2]=(REL_VEL);

            out_handle.send(message);

            sleep();

            ///turn them off
            message[0]=(CH_CONSTS::NOTE_OFF+MY_CHANNEL);
            message[1]=(key);
            message[2]=(REL_VEL);
            out_handle.send(message);
        }
    }

    else
        std::cout<<"no ports available";
}
closed account (SECMoG1T)
this is how it work:

you want to generate midi messages from your program, send the messages through a midi output port , the port on the other end is connected to a synthesizer that understands the midi messages and in effect produces the notes encoded by your messages.

as for me, testing your code am using a virtual midi output port because i dont have midi devices connected to my computer, on the other end of the port am using a midi mapper , its an application installed tha i can use to decide where to connect the port above to.

i have connected the port to a virtual synthesizer "coolsoft virtualMIDIsynth 2.5.4" , so whenever i send a message they can be coverted to sound by this snthesizer.

a synthesizer is a basically anything that can understand soundfont files .sf* , that includes virtual synthesizers that you can download, physical instruments such as guitars,pianos,trumpets with midi port that you can connect to using usb cables,jacks etc.

i suggest you go to alsa user interface and select the ports you are using, i don't know if unix have synthesizers installed but i bet they must be there, try connect to the synthesizer you find.

by default windows ships with "Ms GS wavetable synth".
Last edited on
I copied your program from the email the forum sent me into a file called test.cpp. I then built it with the g++ line you previously sent. I started my synth in a screen instance. The output says that it didn't work.

1
2
3
4
5
michael@caitlyn sing $ g++ -Wall -D__LINUX_ALSA__ -o test test.cpp  RtMidi.cpp -lasound -lpthread
michael@caitlyn sing $ ./test

MidiOutAlsa::sendMessage: event parsing error!


I realize that saying "It didn't work" is the epitome of unhelpful in this field. I completely blanked on what I wanted to say....
Thank you for your patience with me.
closed account (SECMoG1T)
i'll test it on a linux machine, 'i'll get back to you.

have any other files including the midiout.cpp or midiprobe.cpp worked for you?
Topic archived. No new replies allowed.