From 8d3d8f8ceb6abd3d39906286a9fb494c5b3c25c6 Mon Sep 17 00:00:00 2001 From: zawz Date: Sat, 17 Aug 2019 01:35:49 +0200 Subject: [PATCH] v1.2 +Added support for new easier map file format +Added version print +Added map output options *Reorganized options *Internal fixes on quotes --- example.mim | 123 +++++++++++++++----------------------- example.zfd | 75 +++++++++++++++++++++++ gen_help_format.sh | 3 +- help_format/command-tags | 9 --- help_format/file-format | 23 -------- help_format/mim-format | 22 +++++++ help_format/zfd-format | 28 +++++++++ include/format.hpp | 12 ++++ include/help.h | 5 +- src/device.cpp | 38 +++++++++--- src/format.cpp | 105 +++++++++++++++++++++++++++++++++ src/main.cpp | 124 ++++++++++++++++++++++++++++----------- 12 files changed, 414 insertions(+), 153 deletions(-) create mode 100644 example.zfd delete mode 100644 help_format/file-format create mode 100644 help_format/mim-format create mode 100644 help_format/zfd-format create mode 100644 include/format.hpp create mode 100644 src/format.cpp diff --git a/example.mim b/example.mim index a458ebd..467b9b4 100644 --- a/example.mim +++ b/example.mim @@ -1,78 +1,49 @@ -[ -// LAUNCH CONTROL -{ - name=Launch Control - commands=[ - // KNOBS HIGH - { - //KNOB HA - //displays value 0:127 for knobs 21-28 - type=controller - id=21:28 - shell=echo "Knob #$id ch$channel:$value" - }, - // KNOBS LOW - { - //KNOB L1 - //displays value 0:127 for knob 41 from any channel - type=controller - id=41 - channel=* - shell=echo "Knob #$id ch$channel:$value" - }, - { - //KNOB L2 - //displays value -100:100 for knob 42 on channel 0 - type=controller - id=42 - channel=0 - remap=-100:100 - shell=echo "Knob #$id ch$channel:$value r:$rawvalue" - }, - { - //KNOB L3 H1 - //displays value 0:1:0 for knob 42 on channel 1 (first half) - type=controller - id=42 - channel=1 - range=0:63 - remap=0:1 - float=true - shell=echo "Knob #$id ch$channel:$value" - }, - { - //KNOB L3 H2 - //displays value 0:1:0 for knob 42 on channel 1 (second half) - type=controller - id=42 - channel=1 - range=64:127 - remap=1:0 - float=true - shell=echo "Knob #$id ch$channel:$value" - } - ] -} -, -// LAUNCHPAD -{ - name=Launchpad S - commands=[ - { - // ANY NOTE ON - type=note - id=* - shell=echo "Note $id on velocity:$velocity" - }, - { - // ANY NOTE OFF - type=note - id=* - trigger=0 - shell=echo "Note $id off" - } - ] -} -] +Device "Launch Control" + + //display value 0:127 for knobs 21-28 + Command controller + id=21:28 + shell=echo "Knob #$id ch$channel:$value" + + //display value 0:127 for knob 41 from any channel + Command controller + id=41 + channel=* + shell=echo "Knob #$id ch$channel:$value" + + //display value -100:100 for knob 42 on channel 0 + Command controller + id=42 + channel=0 + remap=-100:100 + shell=echo "Knob #$id ch0:$value r:$rawvalue" + + //display value 0:1:0 for knob 42 on channel 1 (first half) + Command controller + id=42 + channel=1 + range=0:63 + remap=0:1 + float=true + shell=echo "Knob #$id ch1:$value r:$rawvalue" + + //display value 0:1:0 for knob 42 on channel 1 (second half) + Command controller + id=42 + channel=1 + range=64:127 + remap=1:0 + float=true + shell=echo "Knob #$id ch1:$value r:$rawvalue" + + +Device "Launchpad S" + + Command note + shell=echo "Note $id on velocity:$velocity" + + Command note + trigger=0 + shell=echo "Note $id off" diff --git a/example.zfd b/example.zfd new file mode 100644 index 0000000..1e04d13 --- /dev/null +++ b/example.zfd @@ -0,0 +1,75 @@ +[ + +// LAUNCH CONTROL +{ + name=Launch Control + commands=[ + // KNOBS HIGH + { + //KNOB HA + //displays value 0:127 for knobs 21-28 + type=controller + id=21:28 + shell=echo "Knob #$id ch$channel:$value" + }, + // KNOBS LOW + { + //KNOB L1 + //displays value 0:127 for knob 41 from any channel + type=controller + id=41 + shell=echo "Knob #$id ch$channel:$value" + }, + { + //KNOB L2 + //displays value -100:100 for knob 42 on channel 0 + type=controller + id=42 + channel=0 + remap=-100:100 + shell=echo "Knob #$id ch0:$value r:$rawvalue" + }, + { + //KNOB L3 H1 + //displays value 0:1:0 for knob 42 on channel 1 (first half) + type=controller + id=42 + channel=1 + range=0:63 + remap=0:1 + float=true + shell=echo "Knob #$id ch1:$value r:$rawvalue" + }, + { + //KNOB L3 H2 + //displays value 0:1:0 for knob 42 on channel 1 (second half) + type=controller + id=42 + channel=1 + range=64:127 + remap=1:0 + float=true + shell=echo "Knob #$id ch1:$value r:$rawvalue" + } + ] +} +, +// LAUNCHPAD +{ + name=Launchpad S + commands=[ + { + // ANY NOTE ON + type=note + shell=echo "Note $id on velocity:$velocity" + }, + { + // ANY NOTE OFF + type=note + trigger=0 + shell=echo "Note $id off" + } + ] +} + +] diff --git a/gen_help_format.sh b/gen_help_format.sh index 987ef15..256da27 100755 --- a/gen_help_format.sh +++ b/gen_help_format.sh @@ -3,7 +3,8 @@ IDIR=include cp $FORMAT_FOLDER/help_template_head $IDIR/help.h -echo "#define FILE_FORMAT \"zmidimap$(sed -n -e 'H;${x;s/\n/\\n/g;s/^,//;p;}' $FORMAT_FOLDER/file-format)\"" >> $IDIR/help.h +echo "#define ZFD_FORMAT \"zmidimap$(sed -n -e 'H;${x;s/\n/\\n/g;s/^,//;p;}' $FORMAT_FOLDER/zfd-format)\"" >> $IDIR/help.h +echo "#define MIM_FORMAT \"zmidimap$(sed -n -e 'H;${x;s/\n/\\n/g;s/^,//;p;}' $FORMAT_FOLDER/mim-format)\"" >> $IDIR/help.h echo "#define SHELL_FORMAT \"zmidimap$(sed -n -e 'H;${x;s/\n/\\n/g;s/^,//;p;}' $FORMAT_FOLDER/shell-format)\"" >> $IDIR/help.h echo "#define COMMAND_TAGS \"zmidimap$(sed -n -e 'H;${x;s/\n/\\n/g;s/^,//;p;}' $FORMAT_FOLDER/command-tags)\"" >> $IDIR/help.h diff --git a/help_format/command-tags b/help_format/command-tags index ecda04c..3133144 100644 --- a/help_format/command-tags +++ b/help_format/command-tags @@ -1,14 +1,5 @@ -- [COMMAND TAGS] -- -[Global tags] - type= - shell= --- - *type: type of the signal: note/controller/pitch/system/connect/disconnect - > mandatory - *shell: shell command to be executed - > mandatory - [Note tags] id= channel= diff --git a/help_format/file-format b/help_format/file-format deleted file mode 100644 index c01717f..0000000 --- a/help_format/file-format +++ /dev/null @@ -1,23 +0,0 @@ --- [FILE FORMAT] -- - -[,] - - format - { - name= - commands=[,] - } --- - *name: string referring to client name of the device - - format - { - = - = - ... - } --- - value can be concatenated with \"\" or '' - see command-tags - -Full info on file format: https://github.com/zawwz/zFiledat diff --git a/help_format/mim-format b/help_format/mim-format new file mode 100644 index 0000000..733d448 --- /dev/null +++ b/help_format/mim-format @@ -0,0 +1,22 @@ +-- [MIM FILE FORMAT] -- + +Device + Command + shell= + = + = + ... + +Device +... + +-- +*name: string referring to client name of the device + > mandatory +*type: type of the signal: note/controller/pitch/system/connect/disconnect + > mandatory +*shell: shell command to be executed + > mandatory + +Shell command can be concatenated with \"\" or '' +see --command-tags for optional command tags diff --git a/help_format/zfd-format b/help_format/zfd-format new file mode 100644 index 0000000..f69ec33 --- /dev/null +++ b/help_format/zfd-format @@ -0,0 +1,28 @@ +-- [ZFD FILE FORMAT] -- + +[,] + +-- format -- + { + name= + commands=[,] + } +-- +*name: string referring to client name of the device + + format + { + type= + shell= + = + = + ... + } +-- +*type: type of the signal: note/controller/pitch/system/connect/disconnect + > mandatory +*shell: shell command to be executed + > mandatory + +Shell command can be concatenated with \"\" or '' +see --command-tags for optional command tags diff --git a/include/format.hpp b/include/format.hpp new file mode 100644 index 0000000..f19cc65 --- /dev/null +++ b/include/format.hpp @@ -0,0 +1,12 @@ +#ifndef FORMAT_HPP +#define FORMAT_HPP + +#include + +ztd::chunkdat mimtochk(const std::string& mim); + +std::string file_strimport(const std::string& path); + +bool is_mim(const std::string& str); + +#endif //FORMAT_HPP diff --git a/include/help.h b/include/help.h index c5f1d5d..bb2eeac 100644 --- a/include/help.h +++ b/include/help.h @@ -1,6 +1,7 @@ #ifndef HELP_H #define HELP_H -#define FILE_FORMAT "zmidimap\n-- [FILE FORMAT] --\n\n[,]\n\n format\n {\n name=\n commands=[,]\n }\n--\n *name: string referring to client name of the device\n\n format\n {\n =\n =\n ...\n }\n--\n value can be concatenated with \"\" or ''\n see command-tags\n\nFull info on file format: https://github.com/zawwz/zFiledat" +#define ZFD_FORMAT "zmidimap\n-- [ZFD FILE FORMAT] --\n\n[,]\n\n-- format --\n {\n name=\n commands=[,]\n }\n--\n*name: string referring to client name of the device\n\n format\n {\n type=\n shell=\n =\n =\n ...\n }\n--\n*type: type of the signal: note/controller/pitch/system/connect/disconnect\n > mandatory\n*shell: shell command to be executed\n > mandatory\n\nShell command can be concatenated with \"\" or ''\nsee --command-tags for optional command tags" +#define MIM_FORMAT "zmidimap\n-- [MIM FILE FORMAT] --\n\nDevice \n Command \n shell=\n =\n =\n ...\n\nDevice \n...\n\n--\n*name: string referring to client name of the device\n > mandatory\n*type: type of the signal: note/controller/pitch/system/connect/disconnect\n > mandatory\n*shell: shell command to be executed\n > mandatory\n\nShell command can be concatenated with \"\" or ''\nsee --command-tags for optional command tags" #define SHELL_FORMAT "zmidimap\n-- [SHELL FORMAT] --\n\nShell command follows regular shell format\n\n-- [Environment] --\n\n[Note]\n $id: id of the note\n $channel: channel of the note\n $velocity: velocity of the note\n\n[Controller]\n $value: value of the controller (remapped)\n $id: id of the controller\n $channel: channel of the controller\n $rawvalue: original value of the controller\n\n[Pitch]\n $value: value of the bend (remapped)\n $rawvalue: original value of the bend\n\n[System]\n $code: hexadecimal code of the system signal" -#define COMMAND_TAGS "zmidimap\n-- [COMMAND TAGS] --\n\n[Global tags]\n type=\n shell=\n--\n *type: type of the signal: note/controller/pitch/system/connect/disconnect\n > mandatory\n *shell: shell command to be executed\n > mandatory\n\n[Note tags]\n id=\n channel=\n trigger=\n--\n *id: note id from 0 to 127\n > optional, default 0:127\n *channel: value from 0 to 16 for channel, * for any channel\n > optional, default *\n *trigger: note velocity from 0 to 127 that triggers the command\n > optional, default 1:127\n\n[Controller tags]\n id=\n channel=\n range=\n remap=\n float=\n--\n *id: controller id from 0 to 127\n > optional, default 0:127\n *channel: value from 0 to 16 for channel, * for any channel\n > optional, default *\n *range: controller value from 0 to 127 that triggers command\n > optional, default 0:127\n *remap: remaps the range to given interval\n > optional, default same as range\n *float: boolean value defining if output is a floating point value\n > optional, default false\n\n[Pitch bend tags]\n range=\n remap=\n float=\n--\n *range: controller value from -8192 to 8191 that triggers command\n > optional, default -8192:8191\n *remap: remaps the range to given interval\n > optional, default same as range\n *float: boolean value defining if output is a floating point value\n > optional, default false\n\n[Interval Format]\n x:y range from x to y\n x single value x\n * all possible values" +#define COMMAND_TAGS "zmidimap\n-- [COMMAND TAGS] --\n\n[Note tags]\n id=\n channel=\n trigger=\n--\n *id: note id from 0 to 127\n > optional, default 0:127\n *channel: value from 0 to 16 for channel, * for any channel\n > optional, default *\n *trigger: note velocity from 0 to 127 that triggers the command\n > optional, default 1:127\n\n[Controller tags]\n id=\n channel=\n range=\n remap=\n float=\n--\n *id: controller id from 0 to 127\n > optional, default 0:127\n *channel: value from 0 to 16 for channel, * for any channel\n > optional, default *\n *range: controller value from 0 to 127 that triggers command\n > optional, default 0:127\n *remap: remaps the range to given interval\n > optional, default same as range\n *float: boolean value defining if output is a floating point value\n > optional, default false\n\n[Pitch bend tags]\n range=\n remap=\n float=\n--\n *range: controller value from -8192 to 8191 that triggers command\n > optional, default -8192:8191\n *remap: remaps the range to given interval\n > optional, default same as range\n *float: boolean value defining if output is a floating point value\n > optional, default false\n\n[Interval Format]\n x:y range from x to y\n x single value x\n * all possible values" #endif //HELP_H diff --git a/src/device.cpp b/src/device.cpp index 8b6f316..9e1405b 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -11,6 +11,30 @@ std::vector device_list; +static std::string dequote(const std::string& in) +{ + std::string ret; + const char quote = in[0]; + if(quote != '\'' && quote !='\"') + return in; + unsigned int i=1; + while(i='0' && a<='9'); @@ -111,7 +135,7 @@ bool importBool(ztd::chunkdat const& ch, std::string const& tag, bool defbool) bool Device::import_chunk(ztd::chunkdat const& ch) { ztd::chunkdat& cch = ch["commands"]; - this->name=ch["name"].strval(); + this->name=dequote(ch["name"].strval()); for(int i=0 ; isysCommands ) { std::string command="code=" + strval + ";"; - command += it.shell; + command += dequote(it.shell); std::thread(sh, command).detach(); } } @@ -347,7 +371,7 @@ void Device::run_signal(char* buff) std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";velocity=" + std::to_string(value) + ";"; - command += it.shell; + command += dequote(it.shell); std::thread(sh, command).detach(); } } @@ -374,7 +398,7 @@ void Device::run_signal(char* buff) command += std::to_string(result); else command += std::to_string((long int) result); - command += ";" + it.shell; + command += ";" + dequote(it.shell); std::thread(sh, command).detach(); } } @@ -400,7 +424,7 @@ void Device::run_signal(char* buff) command += std::to_string(result); else command += std::to_string((long int) result); - command += ";" + it.shell; + command += ";" + dequote(it.shell); std::thread(sh, command).detach(); } } @@ -423,7 +447,7 @@ void Device::loop(Device* dev) for( auto it : dev->connectCommands ) { - std::thread(sh, it.shell).detach(); + std::thread(sh, dequote(it.shell)).detach(); } while (getline(&buff, &buff_size, stream) > 0) @@ -433,7 +457,7 @@ void Device::loop(Device* dev) for( auto it : dev->disconnectCommands ) { - std::thread(sh, it.shell).detach(); + std::thread(sh, dequote(it.shell)).detach(); } log("Device '" + dev->name + "' disconnected\n"); diff --git a/src/format.cpp b/src/format.cpp new file mode 100644 index 0000000..d5a5bd9 --- /dev/null +++ b/src/format.cpp @@ -0,0 +1,105 @@ +#include "format.hpp" + +static void _skipline(const std::string& mim, unsigned int& i) +{ + while(i #include #include +#define VERSION_STRING "v1.2" + ztd::option_set options; void help() { - printf("zmidimap [options] \n\nOptions:\n"); - options.print_help(2, 25); - printf("\nSee --file-format --command-tags --shell-format options for details on map file format\n"); + printf("zmidimap [options] \n\nOptions:\n"); + options.print_help(4, 25); + printf("\nSee --zfd-format --command-tags --shell-format options for details on map file format\n"); +} + +void version() +{ + printf("zmidimap %s\n", VERSION_STRING); } void option_p(const std::string& port) @@ -67,14 +76,27 @@ int main(int argc, char* argv[]) if (!isatty(fileno(stdin))) piped = true; - options.add(ztd::option('h',"help", false, "Display this help message")); - options.add(ztd::option("file-format", false, "Display file format help")); - options.add(ztd::option("command-tags", false, "Display for command tag help")); - options.add(ztd::option("shell-format", false, "Display for shell format help")); - options.add(ztd::option('l',"list", false, "List detected devices")); - options.add(ztd::option('L',"full-list", false, "Print whole device list details")); - options.add(ztd::option('p',"port", true, "Connect to device and output to console", "device")); - options.add(ztd::option("no-log", false, "Disable console logging")); + options.add(ztd::option("\r [Help]")); + options.add(ztd::option('h',"help", false, "Display this help message")); + options.add(ztd::option('v',"version", false, "Display version")); + options.add(ztd::option("mim-format", false, "Display mim file format help")); + options.add(ztd::option("zfd-format", false, "Display zfd file format help")); + options.add(ztd::option("command-tags", false, "Display for command tag help")); + options.add(ztd::option("shell-format", false, "Display for shell format help")); + + options.add(ztd::option("\r [Format]")); + options.add(ztd::option("no-log", false, "Disable console logging")); + + options.add(ztd::option("\r [Devices]")); + options.add(ztd::option('l',"list", false, "List detected devices")); + options.add(ztd::option('L',"full-list", false, "Print whole device list details")); + options.add(ztd::option('p',"port", true, "Connect to device and output to console", "device")); + options.add(ztd::option("\r [Map file]")); + options.add(ztd::option('o',"output", true, "Output the resulting zfd map to file. - for stdout")); + options.add(ztd::option('m',"mim", false, "Read file in mim format")); + options.add(ztd::option('z',"zfd", false, "Read file in zfd format")); + options.add(ztd::option("aligner", true, "String to use for aligning output map format. Default \\t", "string")); + options.add(ztd::option("\rIf no file format is specified, the program will try to guess the format")); // options.add(ztd::option('i',"interactive", false, "Start in interactive mode")); std::vector arg; @@ -84,54 +106,53 @@ int main(int argc, char* argv[]) } catch(ztd::option_error& err) { - printf("Option error: %s\n", err.what()); + printf("%s\n", err.what()); stop(1); } - //exit options ztd::option* op=nullptr; - op = options.find('h'); - if( op->activated ) + //exit options + if( options.find('h')->activated ) { help(); stop(0); } - op = options.find("file-format"); - if( op->activated ) + if( options.find('v')->activated ) { - printf("%s\n", FILE_FORMAT); + version(); stop(0); } - op = options.find("command-tags"); - if( op->activated ) + if( options.find("mim-format")->activated ) + { + printf("%s\n", MIM_FORMAT); + stop(0); + } + if( options.find("zfd-format")->activated ) + { + printf("%s\n", ZFD_FORMAT); + stop(0); + } + if( options.find("command-tags")->activated ) { printf("%s\n", COMMAND_TAGS); stop(0); } - op = options.find("shell-format"); - if( op->activated ) + if( options.find("shell-format")->activated ) { printf("%s\n", SHELL_FORMAT); stop(0); } - op = options.find('h'); - if( op->activated ) - { - help(); - stop(0); - } - op = options.find('L'); - if( op->activated ) + if( options.find('L')->activated ) { sh("aseqdump -l"); stop(0); } - op = options.find('l'); - if( op->activated ) + if( options.find('l')->activated ) { sh(LIST_COMMAND); stop(0); } + op = options.find('p'); if( op->activated ) { @@ -140,11 +161,15 @@ int main(int argc, char* argv[]) } //behavioral options - op = options.find("no-log"); - if( op->activated ) + if( options.find("no-log")->activated ) { log_on=false; } + std::string aligner="\t"; + if(options.find("aligner")->activated) + { + aligner=options.find("aligner")->argument; + } //no argument: display help ztd::filedat file; @@ -175,10 +200,39 @@ int main(int argc, char* argv[]) else { log("Loading map file '" + arg[0] + "'\n"); - file.import_file(); + if(options.find("zfd")->activated) + { + file.import_file(); + } + else if(options.find("mim")->activated) + { + file.data() = mimtochk(file_strimport(arg[0])); + } + else + { + std::string filestr=file_strimport(arg[0]); + if(is_mim(filestr)) + { + file.data() = mimtochk(filestr); + } + else + { + file.import_file(); + } + } } + if(options.find('o')->activated) + { + if(options.find('o')->argument == "-") { + std::cout << file.strval(aligner) << std::endl; + } + else { + } + return 0; + } //create commands + // potential parallel improvement for(int i=0 ; i