Motivation
It is possible to compile from source files for NGC, NGL and NGR rather than type them directly.
The idea here is motivated by my rather massive NG application: 64 encoders, 64 ledrings, 64 RGB LEDs, 24LCD modules organised as over 80 text fields, lots of buttons and normal LEDs. The required NG definition files are also rather massive!
Pre-processing the required NG files has certain advantages in this situation:
- break up the project into multiple files to organise different areas of functionality
- substitute text (e.g values) that occur in many places by a single variable definition, that is easy to change.
- perform mathematical operations that output text parse-able by NG (e.g “value=4” rather than “value=2+2” ,NG cannot process the latter)
- create concise, function like macros that expand to the long winded entries that NG requires.
- perform the calculations and manipulation required to turn user defined data into sysex message defintions
All of this allows rather major changes in structure to be done easily (e.g. add,remove or change the order of a SRIO PCB in the chain) that would otherwise create a horrible amount of typing!
About M4
I tried the C preprocessor, and although it works for include files, and #define for text substitution, that’s about all that can usefully done with it (e.g there is no way to arbitrarily insert a carriage return in the output, for example).
So enter a tool designed for the job: M4
It is free, GNU, cross platform, well documented, powerful, and from what I’ve discovered quite easy to use.
Invocation
The following is in a windows batch file, other OS’s will be similar.
m4 MySource.m4 > MyOutput.ngc
To set up, I simply located m4.exe, and a required dll in my working directory, in the long term it should be located in the system path. The m4 extension on the input file is optional, any extension can be used on input or output.
Include
In the input file any text you want is put, along with any macros you wish to use: first we’ll look at a built in one for including the contents of other files:
RESET_HW
include(`EncoderDefs.m4')
include(`LedRingPatterns.m4')
include(`Buttons.m4')
I this example the contents of 3 files is inserted into the output file along with any other text (i.e preceded with RESET_HW in this example fragment)
Define
To substitute one value for any other use define:
define(`OFFSET',`13')
define(`SomeDefaults',`chn=1 type=CC fwd_to_lcd=1 range=0:127 offset=0 ports=1000100000001000 led_matrix_pattern=3')
EVENT_ENC id=1 fwd_id=LED_MATRIX:eval(OFFSET+1) SomeDefaults
EVENT_ENC id=2 fwd_id=LED_MATRIX:eval(OFFSET+2) SomeDefaults
EVENT_ENC id=3 fwd_id=LED_MATRIX:eval(OFFSET+3) SomeDefaults
This expands to:
EVENT_ENC id=1 fwd_id=LED_MATRIX:14 chn=1 type=CC fwd_to_lcd=1 range=0:127 offset=0 ports=1000100000001000 led_matrix_pattern=3
EVENT_ENC id=2 fwd_id=LED_MATRIX:15 chn=1 type=CC fwd_to_lcd=1 range=0:127 offset=0 ports=1000100000001000 led_matrix_pattern=3
EVENT_ENC id=3 fwd_id=LED_MATRIX:16 chn=1 type=CC fwd_to_lcd=1 range=0:127 offset=0 ports=1000100000001000 led_matrix_pattern=3
note the use of eval() to calculate a value.
There is much, much, more that can be done, but this much should provide some idea, and starting point.
If anyone is interested please post to this thread.