RtMidi MIDI control signals to Ableton Live - c++

I'm trying to write a C++ app using RtMidi to send control signals via my Tascam FireOne MIDI Controller to Ableton Live. So far, I have it successfully sending Note On + Off Signals, Volume Up + Down Signals, etc. via my MIDI Controller to my digital piano using 'a' and 's' keypresses.
// midiout.cpp
#include <iostream>
using namespace std;
#include <signal.h>
#include <windows.h>
#include <conio.h>
#include "RtMidi.h"
int main()
{
std::vector<unsigned char> message;
int i, keyPress;
int nPorts;
char input;
RtMidiOut *midiout = 0;
// midiOUT
try {
midiout = new RtMidiOut();
// Check available ports.
nPorts = midiout->getPortCount();
if ( nPorts == 0 ) {
cout << "No ports available!" << endl;
goto cleanup;
}
// List Available Ports
cout << "\nPort Count = " << nPorts << endl;
cout << "Available Output Ports\n-----------------------------\n";
for( i=0; i<nPorts; i++ )
{
try {
cout << " Output Port Number " << i << " : " << midiout->getPortName(i) << endl;
}
catch(RtError &error) {
error.printMessage();
goto cleanup;
}
}
cout << "\nSelect an output port number :" << endl;
cin >> keyPress;
while( keyPress < 0 || keyPress >= midiout->getPortCount() )
{
cout << "\nIncorrect selection. Please try again :" << endl;
cin >> keyPress;
}
// Open Selected Port
midiout->openPort( keyPress );
keyPress = NULL;
bool done = false;
cout << "Press a key to generate a message, press 'Esc' to exit" << endl;
while(!done)
{
keyPress = _getch();
input = keyPress;
cout << input << " is: " << keyPress << endl;
switch ( keyPress )
{
case 97 :
// Process for keypress = a
// Note On: 144, 60, 90
message.push_back( 144 );
message.push_back( 60 );
message.push_back( 90 );
midiout->sendMessage( &message );
break;
case 115 :
// Process for keypress = s
// Note Off: 128, 60, 90
message.push_back( 128 );
message.push_back( 60 );
message.push_back( 90 );
midiout->sendMessage( &message );
break;
case 27 :
// Process for keypress = esc
done = true;
break;
}
message.clear();
keyPress = NULL;
}
}
catch(RtError &error) {
error.printMessage();
exit( EXIT_FAILURE );
}
cleanup:
delete midiout;
return 0;
}
I tried sending control signals in the same manner as above but this time with control values in the message bytes in place of the note-on or note-off values.
When ableton live is running, I press a key to send a signal but the app locks up and doesn't return to the start of the while loop to receive input from the next keypress.
edit: I've just noticed that even the above code (which usually runs fine) freezes when ableton live is running and I press a key.
further edit: I downloaded a really neat app called MIDI Monitor, which can monitor MIDI data being transferred: http://obds.free.fr/midimon -- my MIDI controller device has two ports -> one for MIDI and one for control. When I'm monitoring control, I can send midi signals and vice versa. However, if, for example, I'm monitoring control and I try to send some CC type data the program locks. Could this be a device driver problem? –
Does anyone know what is going wrong here?

Just one comment - your exception handling is a little weird.
I'd wrap the whole code (initialization and all) in a try/catch(RtError &err) block, and lose most of the other try/catch blocks.
In particular, I don't know what your catch(char * str) stuff will achieve, and you have no catch at all if openPort() throws.

First of all, try sending a different CC and mapping it to some arbitrary control in Ableton, just to see if it's working. The volume controls you are trying to alter behave slightly differently than regular CC's. Specifically, you should check out the MIDI organization's recommended practice for incrementing/decrementing controllers (note that 0x60 == 96), namely when they write:
This parameter uses MSB and LSB separately, with MSB adjusting sensitivity in semitones and LSB adjusting sensitivity in cents. Some manufacturers may even ignore adjustments to the LSB.

Related

How do i detect Key release C++

So i am making a software to help me with an arduino project, it is supossed to be like PUTTY. I programed the arduino to play different notes from Q-I(C4-C5) and the software is supossed to play thoes notes but i need to make it detect when the Key is pressed and released, how do i do that? I searched and found something but it is not working like it's supposed to here is the code:
int main(){
int KeyGet;
while(1)
{
KeyGet = getch();
if (GetKeyState(0x51) & 0x8000)
{
cout<<"key is pressed"<< endl;
}
else if(GetKeyState(0x51)& 0x0001)
{
cout<<"key is released"<< endl;
}
}
return 0;
The program just prints "key is pressed" when i press Q(0x51) and not "key released" as it should, insted it prints "key released" when i press something else other the Q. And i tried GetAsyncKeyState and tried
If (GetKeyState(0x51) != 0)
it still doesent work.
GetKeyState() requires a window and a message loop to keep the state machine updated. But you do not have a message loop. Also, getch() would swallow any key press+release anyway.
Also, GetKeyState(0x51) & 0x0001 is not the right way to detect a key release. That bit is meant for detecting the toggle state of togglable keys like CapsLock, etc.
In your example, you would need to get rid of getch() and use GetAsyncKeyState() instead, eg:
int main(){
bool down = false;
while (1) {
if (GetAsyncKeyState(0x51) < 0) {
if (!down) {
down = true;
cout << "key is pressed" << endl;
}
}
else {
if (down) {
down = false;
cout << "key is released"<< endl;
}
}
Sleep(0);
}
return 0;
}
Otherwise, you can use a WH_KEYBOARD[_LL] hook via SetWindowsHookEx() instead, so you can receive actual key down/up notifications in real-time.

How do I detect keyboard event in background while receiving data from server (C++ TCP Client)

I'm making a multiplayer game with TCP connection between client and server in C++. The client is ment to detect keypresses (arrowkeys) from the console and send data to the server. The server is supposed to send data to all connected clients about player position etc. This means I need to receive data from the server at anytime whilst detecting whenever an arrowkey is pressed in order to send data back to the server. How do I listen for keyevent and receive data at the same time?
I've tried the following, however the loop gets stuck at _getch(); which waits for input.
int keyListener() {
int keypress = _getch();
return keypress;
}
int main() {
int c = 0;
bool run = true;
while (run) {
cout << "Listening to socket" << endl;
c = keyListener();
switch (c) {
case KEY_UP:
cout << "UP" << endl;
break;
case KEY_DOWN:
cout << "DOWN" << endl;
break;
case KEY_LEFT:
cout << "LEFT" << endl;
break;
case KEY_RIGHT:
cout << "RIGHT" << endl;
break;
default:
cout << "Listening for keypress" << endl;
break;
}
}
return 0;
}
You would need more than one book to learn game development. I assume this is just a C++ coding exercise with a "game" theme.
I suggest you create two threads: one to listen to keyboard input and another to handle TCP. You start those threads at the beginning of your game and join them on exit.
The overly simplified game skeleton may look like this:
#include <atomic>
#include <thread>
#include <queue>
#include <mutex>
#include <conio.h>
std::atomic<bool> run = true;
std::queue<int> input;
std::mutex guard; // to protects input queue
void keyboard()
{
while (run)
{
int keypress = _getch();
// TODO: if keypress indicates Exit - set run = false;
// Lock the queue for safe multi-thread access
{
const std::lock_guard<std::mutex> lock(guard);
input.push(keypress);
}
}
}
int main()
{
std::thread keyListener(keyboard);
// TODO: start your TCP thread
while (run)
{
// 1. Process input (keyboard, mouse, voice, etc.)
{
// Lock the queue for safe multi-thread access
const std::lock_guard<std::mutex> lock(guard);
// Pop all collected keys and process them
while (!input.empty())
{
int keypress = input.front();
input.pop();
// TODO: Send game-related keys to the TCP thread
}
}
// 2. Process TCP input, probably with another queue
// 3. Update the Game World
// 4. Display the Game World
}
keyListener.join();
// TODO: join your TCP thread
}

c++ raspberry pi 4 - Get keyboard keys input without enter/validation?

I've been searching for a while, and I don't achieve to find any way to get the input keys of my keyboard, to use them in my program...
Context : I'm starting on robotics, and C++, and I'd simply like to command a motor.
The idea is that "if I press the up arrow, the motor turns, if I press the down arrow, the motor stops" and that's it, no need to validate something or anything like that...
I am with raspbian, through VNC (controlling from my real computer), and the actual code is executed in the terminal.
I'll see later on to make that more complex.
I went through 20 or more pages and didn't find anything helpful... Isn't there an easy way to do something that seems so basically useful?
Some spoke about conio library, but apparently it's outdated, curses/ncurses took its place,but I didn't achieve to find/have anything working...
http://www.cplusplus.com/forum/general/74211/
Create a function to check for key press in unix using ncurses
Capture characters from standard input without waiting for enter to be pressed
This is apparently C code, and not C++, moreover, I don't really understand that...
How to detect key presses in a Linux C GUI program without prompting the user?
This, maybe? But it makes no sense to me (beginner in C++)
How can I get the keyboard state in Linux?
here they speak of "allegro", but apparently, it don't work on the PI 45 yet... and no idea how to install that anyway
http://www.cplusplus.com/forum/general/47357/
Does someone knows a simple little code that I can copy-past to do that, or any way? I'm quite shocked to not have something similar to windows C++ programming where it seems so simple
I mean something like "Keyboard.GetKeyStates(Key)"
I'll continue my research anyway, but please, help !
EDIT :
Apparently, the library SDL (SDL2) can help me do this...
I tried to implement it, it doesn't give any result...
Here is the code I got up to now (I deleted a good part that is useless in here), basically, it's a copy-past from internet SDL official web page :
#include <iostream>
#include <wiringPi.h> //Raspberry pi GPIO Library
#include <cstdio>
#include <csignal>
#include <ctime>
#include <chrono> //library for counting time
#include <thread> //for "this thread sleep"
#include <SDL2/SDL.h> //for getting the keyboard buttons events
bool RUNNING = true; // global flag used to exit from the main loop
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
GPIO Pins definition
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
int SPser = 13, SPclk = 19, SPrclk = 26; //Define the output pins used
int Optocoupler = 17; //define the input pins used
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
SDL definition
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
//void PrintKeyInfo( SDL_KeyboardEvent *key );
//void PrintModifiers( SDLMod mod );
//SOME CODE
// Callback handler if CTRL-C signal is detected
void my_handler(int s) {
std::cout << "Detected CTRL-C signal no. " << s << '\n';
RUNNING = false;
}
//###################################################################################
int main(int argc, char *args[]) {
// Initialize wiringPi and allow the use of BCM pin numbering
wiringPiSetupGpio();
//Initialize SDL
if (SDL_Init(SDL_INIT_EVENTS) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
else
{
SDL_Log("SDL initialized");
}
SDL_Event event;
// Register a callback function to be called if the user presses CTRL-C
std::signal(SIGINT, my_handler);
while(RUNNING)
{
while( SDL_PollEvent( &event ) )
{
std::cout << "SDL While \n" << '\n';
//When the user presses a key
switch( event.type )
{
case SDL_KEYDOWN:
std::cout << "Key press detected \n" << '\n';
//printf( "Key press detected\n" );
break;
case SDL_KEYUP:
std::cout << "Key release detected \n" << '\n';
//printf( "Key release detected\n" );
break;
default:
break;
}
}
//std::cout << "Works??" << '\n';
/*for( i = 0; i <= 15; i++ )
{
//std::cout << "data input i =" << i << '\n';
if (i==0){
//std::cout << "if array " << i << '\n';
DataArr[i]=1;
DataArr[15]=0;
}
else{
j=i-1;
DataArr[j]=0;
DataArr[i]=1;
//std::cout << "in else i" << i << " and j " << j << '\n';
}
SendData(DataArr);
}*/
}
std::cout << "Program ended ...\n";
}
As I followed "dumbly" the tutorial, this should work, but the while loop is never entered as the "std::cout << "SDL While \n" << '\n';" is never shown...
But, as it achieve to compile, I guess the SDL library was installed correctly and things work...
When executing the code, it writes "SDL initialized", then, nothing... pressing keys do nothing
I'm still not sure how to check if the library is installed correctly, but when I type in de command prompt "sudo apt-get install libsdl2-dev", it shows a few lines and says "0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded"
If you are on linux, you should use termios to stop the buffering
#include <termios.h>
void set_no_buffer()
{
struct termios term;
tcgetattr(0, &term);
term.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &term);
}
and then getchar() to get a character without entering

How to do: when we press and hold, program just do once?

I am making a game console with C++, I have a problem. When I press SPACE, my car in my game will jump. When I press and hold keyboard, my car will jump many times. I want: when I hold SPACE keyboard my car just jump once.
How to do this ?
I have read many topics about GetAsyncKeyState() but I don't know how to use it for my game.
if ( _kbhit() )
{
char key = _getch();
if ((key == 75) && (car.position.x > 2))
{
car.position.x -= 3;
}
else if ((key == 77) && (car.position.x < 24))
{
car.position.x += 3;
}
else if ((key == 32) && (car.position.y > 2))
{
car.position.y -= 5;
}
}
Below I have an example software of one possible way to 'filter' duplicate space chars out of an input stream.
The idea relies on the use of two threads.
Thrd1 reads from a stringstream called ssIn. (Replaced with cin in your code.)
Thrd1 (a filter) detects and discards back-to-back space chars, and only sends the first (of multiple space chars) to thrd2.
Thrd2 - reads from the single char buffer filled by thrd1 which will never see back-to-back space characters.
The 2 thrds are synchronized by a pair of semaphores (not mutex).
In my example, for my convenience, I used my version of a Posix semaphore. I do not know if you have Posix, but I am confident you will easily find many example C++ semaphores available on the web, even within SO, and most using only C++ features.
Note that this is only 1 test ... the alphabet with 1,000,000 spaces injected after 'j'. This is not a thourough test. There probably will be other issues to deal with. I have installed a harsh handling of input mis-behaviour. The assert will help you identify the issues.
"thrd2" represents your toe-hold into this example. Thrd2 receives the filtered stream.
#include "../../bag/src/dtb_chrono.hh"
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
using std::chrono::duration_cast;
#include <iostream>
using std::cout, std::flush, std::endl;
//using std::cin;
#include <thread>
using std::thread, std::this_thread::sleep_for;
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
// Posix Process Semaphore, local mode, unnamed, unlocked
#ifndef DTB_PPLSEM_HH
#include "../../bag/src/dtb_pplsem.hh"
using DTB::PPLSem_t;
#endif
// string ops
#ifndef DTB_SOPS_HH
#include "../../bag/src/dtb_sops.hh"
using DTB::SOps_t;
#endif
#include <cassert>
namespace DTB
{
class T946_t
{
public:
int operator()(int argc, char* argv[]) // functor entry
{ return exec(argc, argv); }
private:
// uses compiler provided default ctor and dtor
// Posix Process Semaphore, local mode (unnamed, unshared)
// initial value unlocked
PPLSem_t th1Sem;
PPLSem_t th2Sem;
char kar = '\n';
bool done = false;
size_t m_rdy;
thread* th1;
string th1Log;
thread* th2;
string th2Log;
stringstream ssIn; // debug - replaces cin
stringstream ss1DR; // th1 delay'd report
stringstream ss2DR; // th2 delay'd report
// utilities
SOps_t sops; // string ops - digiComma
int exec(int , char** )
{
// test init: insert a possible user input into ssIn
init_ssIn();
int retVal = 0;
Time_t start_ns = HRClk_t::now();
th1Sem.lock(); // block until threads are ready
th2Sem.lock(); // block
// start ---------vvvvvvvvvvvvvvvvvvv
th1 = new thread(&T946_t::thrd1, this);
assert(nullptr != th1);
while (0 == (m_rdy & 0x01))
std::this_thread::sleep_for(10ms);
// start ---------vvvvvvvvvvvvvvvvvv
th2 = new thread(&T946_t::thrd2, this);
assert(nullptr != th2);
while (0 == (m_rdy & 0x02))
std::this_thread::sleep_for(10ms);
th1Sem.unlock();
// spin wait for threads to complete
while (!done)
{
std::this_thread::sleep_for(100ms);
}
th1->join();
th2->join();
cout << "\n join()'s complete";
auto duration_ns = duration_cast<NS_t>(HRClk_t::now() - start_ns).count();
cout << "\n T901_t::exec() duration "
<< sops.digiComma(duration_ns) << " ns" << endl;
// output the delay'd reports
cout << ss1DR.str() << ss2DR.str() << endl;
return retVal;
}
void init_ssIn()
{
ssIn << "abcdefghij";
for (int i=0; i<1000001; ++i) ssIn << ' ';
std::string::size_type k = ssIn.str().size();
ssIn << "klmnopqrstuvwxyz";
// a..j
cout << "\n ssIn: '" << ssIn.str().substr(0, 10)
<< " ...spaces... " << ssIn.str().substr(k, 16) << "'"
<< "\n ssIn.str().size(): "
<< sops.digiComma(ssIn.str().size()) << endl;
}
void thrd1()
{
uint64_t th1Count = 0;
uint64_t th1Skips = 0;
char lkar = '\0';
m_rdy |= 0x01; // sync msg to main
do {
getNextKar(lkar); // read from input (ssIn or cin)
th1Sem.lock(); // wait for thrd2 to give permission
{
if(' ' == lkar) // current input kar
{
if(' ' == kar) // previous kar
{
// filter out back-to-back space chars
th1Skips += 1;
th1Sem.unlock(); // skip the handshake, no char to send,
// give self permission-to-proceed
continue;
}
}
// else, not a duplicate space
th1Count += 1;
kar = lkar; // write to input of thrd2
th1Log += lkar; // log
lkar = ' ';
}
th2Sem.unlock(); // give thrd2 permission-to-proceed
if (ssIn.eof())
{
done = true;
break;
}
}while(!done);
ss1DR
<< "\n th1Count " << sops.digiComma(th1Count)
<< "\n th1Skips " << sops.digiComma(th1Skips)
<< "\n th1Log " << th1Log
<< "\n thrd1 exit " << endl;
}
// read from ssIn for development
// read from cin for app
void getNextKar(char& lkar)
{
// ssIn >> lkar; // reads 1 char, but skips multiple blank chars
// lkar = ssIn.get(); returns an integer (not a char)
(void)ssIn.get (lkar);
if(ssIn.fail())
{
if(ssIn.eof()) return; // not a fail
assert(0); // harsh exit, might want something gentler
}
}
void thrd2()
{
uint64_t th2Count = 0;
m_rdy |= 0x02; // sync msg to main
do {
th2Sem.lock(); // wait for thrd1 to give permission
char t = kar;
th1Sem.unlock(); // give permission-to-proceed to thrd1
// simulate application - no duplicate spaces from input
th2Log += t;
th2Count += 1;
// end of sim
}while(!done);
ss2DR
<< "\n th2Count " << sops.digiComma(th2Count)
<< "\n th2Log " << th2Log
<< "\n thrd2 exit " << endl;
}
}; // class T946_t
} // namespace DTB
int main(int argc, char* argv[]) { return DTB::T946_t()(argc, argv); }
The output looks like:
ssIn: 'abcdefghij ...spaces... klmnopqrstuvwxyz'
ssIn.str().size(): 1,000,027
join()'s complete
T901_t::exec() duration 120,421,582 ns
th1Count 28
th1Skips 1,000,000
th1Log abcdefghij klmnopqrstuvwxyz
thrd1 exit
th2Count 28
th2Log abcdefghij klmnopqrstuvwxyz
thrd2 exit
The duration is 120 ms for 1 Million chars input.
As #Remy Lebeau pointed out you can get the repeat count by install WH_KEYBOARD hook and filter the key held pressed in KeyboardProc.
Of course, for simple, no need install a hook you can filter repeat WM_KEYDOWN messages in window procedure when you press the space key and hold. The following is an example you can refer to:
case WM_KEYDOWN:
if (wParam == VK_SPACE)
{
if (!((HIWORD(lParam) & 0x4000) || (HIWORD(lParam) & 0x8000)))
{
isKeyHold = TRUE; // First time pressed
OutputDebugString(TEXT("pressed !\n"));
}
else if (isKeyHold && (HIWORD(lParam) & 0x4000))
{
OutputDebugString(TEXT("hold !\n"));
return 1; // Don't handle the message when the key is pressed and held.
}
}
break;
case WM_KEYUP:
if (wParam == VK_SPACE && isKeyHold)
{
isKeyHold = FALSE; // Clear the isKeyHold flag when release the key.
OutputDebugString(TEXT("release !\n"));
}
break;

C++: Reading characters before pressing ENTER

for like few hours now, I am trying to figure out how to read characters from cin before pressing ENTER (by using threads). I know about conio.h library but I prefer not to use it.
I wrote simple program that gets data from user and saves it in 'msg' string. Program has child thread that clears the console every second. What I want to do is:
User puts some data but doesn't press ENTER so it's not saved in 'msg' variable.
Console clears
send to cout the characters user typed, so he won't even notice that console was cleared.
PS. Sorry for my english, here's the program:
#include<iostream>
#include<string>
#include<winsock2.h>
#include<process.h>
#include<windows.h>
using namespace std;
void __cdecl ThreadProc( void * Args )
{
while( true ){
system("cls");
cout << "Input: ";
/*
char c;
while((c=cin.peek()) != '\n')
cin.get(c);
cout << c;
*/
Sleep(1000);
}
_endthread();
}
int main(){
HANDLE hThread =( HANDLE ) _beginthread( ThreadProc, 0, NULL );
while (true){
string msg;
getline(cin,msg);
cout << "MSG:" << msg << endl;
cin.clear();
fflush(stdin);
}
return 0;
}
EDIT:
Key-logger? Nah, I am doing console network chat. Currently server and client can chat with each-other. When new message is received or sent, it is saved in "vector<\string> chat" and console is refreshed below code:
void show_chat(){
system("cls");
for(unsigned int i =0;i<chat.size();i++){
cout << "[" << date[i].tm_hour << ":" << date[i].tm_min << ":" << date[i].tm_sec << "] " << chat[i] << endl;
}
cout << "Input: ";
}
So there is a problem if new message is received while user is writing his own message. Part of the message written before message system("cls") is lost on the screen.
To do what you want, you will need to incorporate a message queue and update method.
Can you do it the way you have presented? Sure, but it's going to be a major pain and there's no way to do this with cin.
Simply have a message queue on both sides, a current status of each client(able_to_receive_messages, unable, etc), and an update method that is called by each client is run after the user is once again able to receive messages.