Added range support to id flag
This commit is contained in:
parent
ccac17666a
commit
94e534f151
4 changed files with 164 additions and 138 deletions
37
README
37
README
|
|
@ -49,17 +49,17 @@ $rawvalue: original value of the bend
|
||||||
|
|
||||||
- <device> format:
|
- <device> format:
|
||||||
{
|
{
|
||||||
name=<name>
|
name=<name>
|
||||||
commands=[<command>,<command>]
|
commands=[<command>,<command>]
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
*name: string referring to client name of the device
|
*name: string referring to client name of the device
|
||||||
|
|
||||||
- <command> format (global):
|
- <command> format (global):
|
||||||
{
|
{
|
||||||
type=<note/controller/pitch>
|
type=<note/controller/pitch>
|
||||||
shell=<shell command>
|
shell=<shell command>
|
||||||
channel=<*/x>
|
channel=<*/x>
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
*type: type of the signal: note/controller/pitch
|
*type: type of the signal: note/controller/pitch
|
||||||
|
|
@ -71,25 +71,25 @@ channel=<*/x>
|
||||||
|
|
||||||
- <command> format (note)
|
- <command> format (note)
|
||||||
{
|
{
|
||||||
id=<x>
|
id=<x/x:y/*>
|
||||||
trigger=<x:y/x>
|
trigger=<x/x:y/*>
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
*id: value from 0 to 127 referring to id of note/controller
|
*id: value from 0 to 127 referring to id of note/controller
|
||||||
> mandatory
|
> optional, default 0:127
|
||||||
*trigger: note velocity from 0 to 127 that triggers the command. Can enter an interval x:y or single value
|
*trigger: note velocity from 0 to 127 that triggers the command. Can enter an interval x:y or single value
|
||||||
> optional, default 1:127
|
> optional, default 1:127
|
||||||
|
|
||||||
- <command> format (controller)
|
- <command> format (controller)
|
||||||
{
|
{
|
||||||
id=<x>
|
id=<x/x:y/*>
|
||||||
range=<x:y>
|
range=<x/x:y/*>
|
||||||
remap=<x:y>
|
remap=<x/x:y/*>
|
||||||
float=<true/false>
|
float=<true/false>
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
*id: value from 0 to 127 referring to id of note/controller
|
*id: value from 0 to 127 referring to id of note/controller
|
||||||
> mandatory
|
> optional, default 0:127
|
||||||
*range: controller value from 0 to 127 that triggers command. Can enter an interval x:y or single value
|
*range: controller value from 0 to 127 that triggers command. Can enter an interval x:y or single value
|
||||||
> optional, default 0:127
|
> optional, default 0:127
|
||||||
*remap: remaps the range to given interval. Interval can be inversed and float
|
*remap: remaps the range to given interval. Interval can be inversed and float
|
||||||
|
|
@ -99,9 +99,9 @@ float=<true/false>
|
||||||
|
|
||||||
- <command> format (pitch)
|
- <command> format (pitch)
|
||||||
{
|
{
|
||||||
range=<x:y>
|
range=<x/x:y/*>
|
||||||
remap=<x:y>
|
remap=<x/x:y/*>
|
||||||
float=<true/false>
|
float=<true/false>
|
||||||
}
|
}
|
||||||
-
|
-
|
||||||
*range: controller value from -8192 to 8191 that triggers command. Can enter an interval x:y or single value
|
*range: controller value from -8192 to 8191 that triggers command. Can enter an interval x:y or single value
|
||||||
|
|
@ -111,4 +111,9 @@ float=<true/false>
|
||||||
*float: boolean value defining if output is a floating point value
|
*float: boolean value defining if output is a floating point value
|
||||||
> optional, default false
|
> optional, default false
|
||||||
|
|
||||||
|
- Format:
|
||||||
|
x:y range from x to y
|
||||||
|
x single value x
|
||||||
|
* all possible values
|
||||||
|
|
||||||
- Comments can be written inside {} by doing //=<COMMENT>
|
- Comments can be written inside {} by doing //=<COMMENT>
|
||||||
|
|
|
||||||
28
example.mim
28
example.mim
|
|
@ -4,15 +4,11 @@
|
||||||
name=Launch Control
|
name=Launch Control
|
||||||
commands=[
|
commands=[
|
||||||
{
|
{
|
||||||
type=note
|
//=KNOB HA
|
||||||
id=9
|
//=displays value 0:127 for knobs 21-28
|
||||||
shell=echo "Note $id on ch$channel v$velocity"
|
type=controller
|
||||||
},
|
id=21:28
|
||||||
{
|
shell=echo "Knob #$id ch$channel:$value"
|
||||||
type=note
|
|
||||||
id=9
|
|
||||||
trigger=0
|
|
||||||
shell=echo "Note $id off ch$channel"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
//=KNOB L1
|
//=KNOB L1
|
||||||
|
|
@ -58,7 +54,19 @@
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
name=Launchpad S
|
name=Launchpad S
|
||||||
commands=[]
|
commands=[
|
||||||
|
{
|
||||||
|
type=note
|
||||||
|
id=*
|
||||||
|
shell=echo "Note $id on velocity:$velocity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type=note
|
||||||
|
id=*
|
||||||
|
trigger=0
|
||||||
|
shell=echo "Note $id off"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
||||||
235
src/device.cpp
235
src/device.cpp
|
|
@ -39,6 +39,70 @@ bool Device::start_loop()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int32_t,int32_t> importRange(Chunk const& ch, std::string const& tag, int32_t low, int32_t high)
|
||||||
|
{
|
||||||
|
Chunk* pch=ch.subChunkPtr(tag);
|
||||||
|
if(pch != nullptr)
|
||||||
|
{
|
||||||
|
std::string str=pch->strval();
|
||||||
|
auto tpos=str.find(':');
|
||||||
|
if (str=="*") //whole range
|
||||||
|
{
|
||||||
|
return std::make_pair(low,high);
|
||||||
|
}
|
||||||
|
else if(tpos == std::string::npos) //single value
|
||||||
|
{
|
||||||
|
low=stoi(str);
|
||||||
|
high=low;
|
||||||
|
}
|
||||||
|
else //range
|
||||||
|
{
|
||||||
|
low=stoi(str.substr(0,tpos));
|
||||||
|
tpos++;
|
||||||
|
high=stoi(str.substr(tpos, str.size()-tpos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_pair(low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float,float> importRangeFloat(Chunk const& ch, std::string const& tag, float low, float high)
|
||||||
|
{
|
||||||
|
Chunk* pch=ch.subChunkPtr(tag);
|
||||||
|
if(pch != nullptr)
|
||||||
|
{
|
||||||
|
std::string str=pch->strval();
|
||||||
|
auto tpos=str.find(':');
|
||||||
|
if(tpos == std::string::npos)
|
||||||
|
{
|
||||||
|
//single value
|
||||||
|
low=stof(str);
|
||||||
|
high=low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//range
|
||||||
|
low=stof(str.substr(0,tpos));
|
||||||
|
tpos++;
|
||||||
|
high=stof(str.substr(tpos, str.size()-tpos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_pair(low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool importBool(Chunk const& ch, std::string const& tag, bool defbool)
|
||||||
|
{
|
||||||
|
Chunk* pch=ch.subChunkPtr(tag);
|
||||||
|
if(pch != nullptr)
|
||||||
|
{
|
||||||
|
std::string str=pch->strval();
|
||||||
|
if( str == "true" )
|
||||||
|
return true;
|
||||||
|
else if( str == "false" )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return defbool;
|
||||||
|
}
|
||||||
|
|
||||||
bool Device::import_chunk(Chunk const& ch)
|
bool Device::import_chunk(Chunk const& ch)
|
||||||
{
|
{
|
||||||
Chunk& cch = ch["commands"];
|
Chunk& cch = ch["commands"];
|
||||||
|
|
@ -56,6 +120,9 @@ bool Device::import_chunk(Chunk const& ch)
|
||||||
int8_t channel;
|
int8_t channel;
|
||||||
std::string shell;
|
std::string shell;
|
||||||
|
|
||||||
|
std::pair<int32_t,int32_t> intpair;
|
||||||
|
std::pair<float,float> floatpair;
|
||||||
|
|
||||||
//channel
|
//channel
|
||||||
if(tch.subChunkPtr("channel") == nullptr || tch["channel"].strval()=="*")
|
if(tch.subChunkPtr("channel") == nullptr || tch["channel"].strval()=="*")
|
||||||
channel=-1;
|
channel=-1;
|
||||||
|
|
@ -68,40 +135,33 @@ bool Device::import_chunk(Chunk const& ch)
|
||||||
//type
|
//type
|
||||||
if(tstr == "note") //type note
|
if(tstr == "note") //type note
|
||||||
{
|
{
|
||||||
uint8_t id;
|
uint8_t id_low=0;
|
||||||
|
uint8_t id_high=127;
|
||||||
uint8_t low=1;
|
uint8_t low=1;
|
||||||
uint8_t high=127;
|
uint8_t high=127;
|
||||||
std::string tt;
|
std::string tt;
|
||||||
|
|
||||||
//id
|
//id
|
||||||
id=stoi(tch["id"].strval());
|
intpair=importRange(tch, "id", id_low, id_high);
|
||||||
|
id_low=intpair.first;
|
||||||
|
id_high=intpair.second;
|
||||||
|
// id=stoi(tch["id"].strval());
|
||||||
|
|
||||||
//trigger
|
//trigger
|
||||||
Chunk* ttch=tch.subChunkPtr("trigger");
|
intpair = importRange(tch, "trigger", low, high);
|
||||||
if(ttch != nullptr)
|
low=intpair.first;
|
||||||
|
high=intpair.second;
|
||||||
|
|
||||||
|
for( uint8_t i=id_low ; i <= id_high ; i++ )
|
||||||
{
|
{
|
||||||
tt=ttch->strval();
|
this->noteCommands[i].push_back(NoteCommand(i,channel,low,high,shell));
|
||||||
auto tpos=tt.find(':');
|
|
||||||
if(tpos == std::string::npos)
|
|
||||||
{
|
|
||||||
//single value
|
|
||||||
low=stoi(tt);
|
|
||||||
high=low;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//range
|
|
||||||
low=stoi(tt.substr(0,tpos));
|
|
||||||
tpos++;
|
|
||||||
high=stoi(tt.substr(tpos, tt.size()-tpos));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this->noteCommands[id].push_back(NoteCommand(id,channel,low,high,shell));
|
|
||||||
this->nb_command++;
|
this->nb_command++;
|
||||||
}
|
}
|
||||||
else if(tstr == "controller") //type controller
|
else if(tstr == "controller") //type controller
|
||||||
{
|
{
|
||||||
uint8_t id;
|
uint8_t id_low=0;
|
||||||
|
uint8_t id_high=127;
|
||||||
uint8_t min=0;
|
uint8_t min=0;
|
||||||
uint8_t max=127;
|
uint8_t max=127;
|
||||||
float mapMin;
|
float mapMin;
|
||||||
|
|
@ -109,55 +169,27 @@ bool Device::import_chunk(Chunk const& ch)
|
||||||
bool floating=false;
|
bool floating=false;
|
||||||
|
|
||||||
//id
|
//id
|
||||||
id=stoi(tch["id"].strval());
|
intpair=importRange(tch, "id", id_low, id_high);
|
||||||
|
id_low=intpair.first;
|
||||||
|
id_high=intpair.second;
|
||||||
|
|
||||||
//range
|
//range
|
||||||
Chunk* ttch=tch.subChunkPtr("range");
|
intpair = importRange(tch, "range", min, max);
|
||||||
if(ttch != nullptr)
|
min=intpair.first;
|
||||||
{
|
max=intpair.second;
|
||||||
std::string range=ttch->strval();
|
|
||||||
auto tpos=range.find(':');
|
|
||||||
if(tpos == std::string::npos)
|
|
||||||
{
|
|
||||||
//single value
|
|
||||||
min=stoi(range);
|
|
||||||
max=min;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//range
|
|
||||||
min=stoi(range.substr(0,tpos));
|
|
||||||
tpos++;
|
|
||||||
max=stoi(range.substr(tpos, range.size()-tpos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//remap
|
//remap
|
||||||
ttch=tch.subChunkPtr("remap");
|
floatpair = importRangeFloat(tch, "remap", min, max);
|
||||||
if(ttch != nullptr)
|
mapMin=floatpair.first;
|
||||||
{
|
mapMax=floatpair.second;
|
||||||
std::string map=ttch->strval();
|
|
||||||
auto tpos=map.find(':');
|
|
||||||
mapMin=stof(map.substr(0,tpos));
|
|
||||||
tpos++;
|
|
||||||
mapMax=stof(map.substr(tpos, map.size()-tpos));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mapMin=min;
|
|
||||||
mapMax=max;
|
|
||||||
}
|
|
||||||
|
|
||||||
//floating
|
//floating
|
||||||
ttch=tch.subChunkPtr("float");
|
floating = importBool(tch, "float", floating);
|
||||||
if(ttch != nullptr)
|
|
||||||
{
|
|
||||||
std::string tfl=ttch->strval();
|
|
||||||
if( tfl == "true" || tfl == "yes" || tfl == "y")
|
|
||||||
floating=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->ctrlCommands[id].push_back(ControllerCommand(id,channel,min,max,mapMin,mapMax,floating,shell));
|
for( uint8_t i=id_low ; i <= id_high ; i++ )
|
||||||
|
{
|
||||||
|
this->ctrlCommands[i].push_back(ControllerCommand(i,channel,min,max,mapMin,mapMax,floating,shell));
|
||||||
|
}
|
||||||
this->nb_command++;
|
this->nb_command++;
|
||||||
}
|
}
|
||||||
else if(tstr == "pitch") //type pitch bend
|
else if(tstr == "pitch") //type pitch bend
|
||||||
|
|
@ -169,45 +201,17 @@ bool Device::import_chunk(Chunk const& ch)
|
||||||
bool floating=false;
|
bool floating=false;
|
||||||
|
|
||||||
//range
|
//range
|
||||||
Chunk* ttch=tch.subChunkPtr("range");
|
intpair = importRange(tch, "range", min, max);
|
||||||
if(ttch != nullptr)
|
min=intpair.first;
|
||||||
{
|
max=intpair.second;
|
||||||
std::string range=ttch->strval();
|
|
||||||
auto tpos=range.find(':');
|
|
||||||
if(tpos == std::string::npos)
|
|
||||||
{
|
|
||||||
//single value
|
|
||||||
min=stoi(range);
|
|
||||||
max=min;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//range
|
|
||||||
min=stoi(range.substr(0,tpos));
|
|
||||||
tpos++;
|
|
||||||
max=stoi(range.substr(tpos, range.size()-tpos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//remap
|
//remap
|
||||||
ttch=tch.subChunkPtr("remap");
|
floatpair = importRangeFloat(tch, "remap", min, max);
|
||||||
if(ttch != nullptr)
|
mapMin=floatpair.first;
|
||||||
{
|
mapMax=floatpair.second;
|
||||||
std::string map=ttch->strval();
|
|
||||||
auto tpos=map.find(':');
|
|
||||||
mapMin=stof(map.substr(0,tpos));
|
|
||||||
tpos++;
|
|
||||||
mapMax=stof(map.substr(tpos, map.size()-tpos));
|
|
||||||
}
|
|
||||||
|
|
||||||
//floating
|
//floating
|
||||||
ttch=tch.subChunkPtr("float");
|
floating = importBool(tch, "float", floating);
|
||||||
if(ttch != nullptr)
|
|
||||||
{
|
|
||||||
std::string tfl=ttch->strval();
|
|
||||||
if( tfl == "true" || tfl == "yes" || tfl == "y")
|
|
||||||
floating=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->pitchCommands.push_back(PitchCommand(channel,min,max,mapMin,mapMax,floating,shell));
|
this->pitchCommands.push_back(PitchCommand(channel,min,max,mapMin,mapMax,floating,shell));
|
||||||
this->nb_command++;
|
this->nb_command++;
|
||||||
|
|
@ -261,7 +265,7 @@ void Device::run_signal(char* buff)
|
||||||
type='p';
|
type='p';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Unknown MIDI signal\n");
|
throw std::runtime_error("Unknown MIDI signal:\n" + std::string(buff));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,7 +277,7 @@ void Device::run_signal(char* buff)
|
||||||
channel = std::stoi( std::string(pos-t, t) );
|
channel = std::stoi( std::string(pos-t, t) );
|
||||||
pos+=2;
|
pos+=2;
|
||||||
|
|
||||||
//ctid read (only note anc controller)
|
//ctid read (only note and controller)
|
||||||
if(type=='n' || type=='c')
|
if(type=='n' || type=='c')
|
||||||
{
|
{
|
||||||
while (*(pos) != ' ')
|
while (*(pos) != ' ')
|
||||||
|
|
@ -300,13 +304,16 @@ void Device::run_signal(char* buff)
|
||||||
else
|
else
|
||||||
value=0;
|
value=0;
|
||||||
|
|
||||||
|
//processing
|
||||||
if (type == 'n')
|
if (type == 'n')
|
||||||
{
|
{
|
||||||
for( auto it : this->noteCommands[ctid])
|
for( auto it : this->noteCommands[ctid] )
|
||||||
{
|
{
|
||||||
if((it.channel == -1 || it.channel == channel) && it.low <= value && it.high >= value)
|
if( (it.channel == -1 || it.channel == channel) && it.low <= value && it.high >= value )
|
||||||
{
|
{
|
||||||
std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";velocity=" + std::to_string(value) + ";";
|
std::string command="id=" + std::to_string(ctid)
|
||||||
|
+ ";channel=" + std::to_string(channel)
|
||||||
|
+ ";velocity=" + std::to_string(value) + ";";
|
||||||
command += it.shell;
|
command += it.shell;
|
||||||
std::thread(sh, command).detach();
|
std::thread(sh, command).detach();
|
||||||
}
|
}
|
||||||
|
|
@ -314,19 +321,22 @@ void Device::run_signal(char* buff)
|
||||||
}
|
}
|
||||||
else if(type == 'c')
|
else if(type == 'c')
|
||||||
{
|
{
|
||||||
for( auto it : this->ctrlCommands[ctid])
|
for( auto it : this->ctrlCommands[ctid] )
|
||||||
{
|
{
|
||||||
if((it.channel == -1 || it.channel == channel) && it.min <= value && it.max >= value)
|
if( (it.channel == -1 || it.channel == channel) && it.min <= value && it.max >= value )
|
||||||
{
|
{
|
||||||
//remapping of value
|
//remapping of value
|
||||||
float result;
|
float result;
|
||||||
if(it.min == it.max)
|
if(it.min == it.max) //zero case
|
||||||
result = it.mapMin;
|
result = it.mapMin;
|
||||||
else
|
else
|
||||||
result=(value-it.min)*(it.mapMax-it.mapMin)/(it.max-it.min)+it.mapMin;
|
result=(value-it.min)*(it.mapMax-it.mapMin)/(it.max-it.min)+it.mapMin;
|
||||||
|
|
||||||
//command execution
|
//command execution
|
||||||
std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";rawvalue=" + std::to_string(value) + ";value=";
|
std::string command="id=" + std::to_string(ctid)
|
||||||
|
+ ";channel=" + std::to_string(channel)
|
||||||
|
+ ";rawvalue=" + std::to_string(value)
|
||||||
|
+ ";value=";
|
||||||
if(it.floating)
|
if(it.floating)
|
||||||
command += std::to_string(result);
|
command += std::to_string(result);
|
||||||
else
|
else
|
||||||
|
|
@ -338,19 +348,21 @@ void Device::run_signal(char* buff)
|
||||||
}
|
}
|
||||||
else if(type == 'p')
|
else if(type == 'p')
|
||||||
{
|
{
|
||||||
for( auto it : this->pitchCommands)
|
for( auto it : this->pitchCommands )
|
||||||
{
|
{
|
||||||
if((it.channel == -1 || it.channel == channel) && it.min <= value && it.max >= value)
|
if( (it.channel == -1 || it.channel == channel) && it.min <= value && it.max >= value )
|
||||||
{
|
{
|
||||||
//remapping of value
|
//remapping of value
|
||||||
float result;
|
float result;
|
||||||
if(it.min == it.max)
|
if(it.min == it.max) //zero case
|
||||||
result = it.mapMin;
|
result = it.mapMin;
|
||||||
else
|
else
|
||||||
result=(value-it.min)*(it.mapMax-it.mapMin)/(it.max-it.min)+it.mapMin;
|
result=(value-it.min)*(it.mapMax-it.mapMin)/(it.max-it.min)+it.mapMin;
|
||||||
|
|
||||||
//command execution
|
//command execution
|
||||||
std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";rawvalue=" + std::to_string(value) + ";value=";
|
std::string command=";channel=" + std::to_string(channel)
|
||||||
|
+ ";rawvalue=" + std::to_string(value)
|
||||||
|
+ ";value=";
|
||||||
if(it.floating)
|
if(it.floating)
|
||||||
command += std::to_string(result);
|
command += std::to_string(result);
|
||||||
else
|
else
|
||||||
|
|
@ -362,6 +374,7 @@ void Device::run_signal(char* buff)
|
||||||
} // if type
|
} // if type
|
||||||
|
|
||||||
} //if system exclusive
|
} //if system exclusive
|
||||||
|
|
||||||
} //while
|
} //while
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ int main(int argc, char* argv[])
|
||||||
Device *newDevice = new Device;
|
Device *newDevice = new Device;
|
||||||
newDevice->import_chunk(file.chunk()[i]);
|
newDevice->import_chunk(file.chunk()[i]);
|
||||||
device_list.push_back(newDevice);
|
device_list.push_back(newDevice);
|
||||||
printf("Added device '%s' with %d commands\n", newDevice->name.c_str(), newDevice->nb_command);
|
printf("Loaded %d commands for device '%s'\n", newDevice->nb_command, newDevice->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue