Merge branch 'poly' of gitea.larke.org:kevin/libcw into poly
# Conflicts: # cwFlow.cpp # cwIoPresetSelApp.cpp # cwLex.cpp # cwLex.h # cwPresetSel.cpp # html/preset_sel/ui.cfg
This commit is contained in:
commit
8dde88f6fd
10
Makefile.am
10
Makefile.am
@ -5,7 +5,7 @@ libcwHDR += src/libcw/cwCommon.h src/libcw/cwCommonImpl.h src/libcw/cwMem.h
|
|||||||
libcwSRC += src/libcw/cwCommonImpl.cpp src/libcw/cwMem.cpp src/libcw/cwLog.cpp src/libcw/cwUtility.cpp
|
libcwSRC += src/libcw/cwCommonImpl.cpp src/libcw/cwMem.cpp src/libcw/cwLog.cpp src/libcw/cwUtility.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwString.h src/libcw/cwMath.h src/libcw/cwVectOps.h src/libcw/cwMtx.h src/libcw/cwVariant.h
|
libcwHDR += src/libcw/cwString.h src/libcw/cwMath.h src/libcw/cwVectOps.h src/libcw/cwMtx.h src/libcw/cwVariant.h
|
||||||
libcwSRC += src/libcw/cwString.cpp src/libcw/cwMath.cpp src/libcw/cwMtx.cpp src/libcw/cwVariant.cpp
|
libcwSRC += src/libcw/cwString.cpp src/libcw/cwMath.cpp src/libcw/cwVectOps.cpp src/libcw/cwMtx.cpp src/libcw/cwVariant.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwB23Tree.h
|
libcwHDR += src/libcw/cwB23Tree.h
|
||||||
libcwSRC += src/libcw/cwB23Tree.cpp
|
libcwSRC += src/libcw/cwB23Tree.cpp
|
||||||
@ -34,8 +34,8 @@ libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp
|
|||||||
libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwDspTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h
|
libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwDspTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h
|
||||||
libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwDspTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp
|
libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwDspTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwFlow.h src/libcw/cwFlowDecl.h src/libcw/cwFlowTypes.h src/libcw/cwFlowProc.h src/libcw/cwFlowCross.h
|
libcwHDR += src/libcw/cwFlow.h src/libcw/cwFlowDecl.h src/libcw/cwFlowTypes.h src/libcw/cwFlowNet.h src/libcw/cwFlowProc.h src/libcw/cwFlowCross.h src/libcw/cwFlowTest.h
|
||||||
libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp
|
libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowNet.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp src/libcw/cwFlowTest.cpp
|
||||||
|
|
||||||
if cwWEBSOCK
|
if cwWEBSOCK
|
||||||
libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h
|
libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h
|
||||||
@ -46,8 +46,8 @@ libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwKeyboard.h
|
libcwHDR += src/libcw/cwKeyboard.h src/libcw/cwTest.h
|
||||||
libcwSRC += src/libcw/cwKeyboard.cpp
|
libcwSRC += src/libcw/cwKeyboard.cpp src/libcw/cwTest.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
||||||
libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp
|
libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp
|
||||||
|
680
README.md
680
README.md
@ -432,7 +432,7 @@ struct in_addr {
|
|||||||
|
|
||||||
export LD_LIBRARY_PATH=~/sdk/libwebsockets/build/out/lib
|
export LD_LIBRARY_PATH=~/sdk/libwebsockets/build/out/lib
|
||||||
|
|
||||||
*** Raspberry Pi Build Notes:
|
### Raspberry Pi Build Notes:
|
||||||
|
|
||||||
cd sdk
|
cd sdk
|
||||||
mkdir libwebsockets
|
mkdir libwebsockets
|
||||||
@ -444,10 +444,10 @@ struct in_addr {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
*** Flow Notes:
|
### Flow Notes:
|
||||||
|
|
||||||
|
|
||||||
- When a variable has a variant with a numberic channel should the 'all' channel variant be removed?
|
- When a variable has a variant with a numeric channel should the 'all' channel variant be removed?
|
||||||
|
|
||||||
- Check for duplicate 'vid'-'chIdx' pairs in var_regster().
|
- Check for duplicate 'vid'-'chIdx' pairs in var_regster().
|
||||||
(The concatenation of 'vid' and 'chIdx' should be unique
|
(The concatenation of 'vid' and 'chIdx' should be unique
|
||||||
@ -469,16 +469,21 @@ specific types, to pass through. For example a 'selector' (n inputs, 1 output) o
|
|||||||
|
|
||||||
DONE: Add a version of var_register() that both registers and returns the value of the variable.
|
DONE: Add a version of var_register() that both registers and returns the value of the variable.
|
||||||
|
|
||||||
*** Flow Instance Creation:
|
### Flow Instance Creation:
|
||||||
|
|
||||||
1. Create all vars from the class description and initially set their
|
0. Parse the 'in' list and create any 'mult' variables whose
|
||||||
value to the default value given in the class. chIdx=kAnyChIdx.
|
'in-var' contains an integer or underscore suffix. See
|
||||||
|
"'in' List Syntax and Semantics" below.
|
||||||
|
|
||||||
|
1. Create all vars from the class description, that were not
|
||||||
|
already instantiated during 'in' list processing, and set their
|
||||||
|
initial value to the default value given in the class. chIdx=kAnyChIdx.
|
||||||
|
|
||||||
Note that all vars must be included in the class description.
|
Note that all vars must be included in the class description.
|
||||||
|
|
||||||
|
|
||||||
2. Apply the preset record from the class description according to the
|
2. Apply the preset records from the class description according to the
|
||||||
label given in the instance definition.
|
'presets' list given in the instance definition.
|
||||||
|
|
||||||
If the variable values are given as a scalar then the existing
|
If the variable values are given as a scalar then the existing
|
||||||
variable is simply given a new value.
|
variable is simply given a new value.
|
||||||
@ -489,17 +494,23 @@ index of the value in the list. This is referred
|
|||||||
to as 'channelizing' the variable because the variable will then
|
to as 'channelizing' the variable because the variable will then
|
||||||
be represented by multiple physical variable records - one for each channel.
|
be represented by multiple physical variable records - one for each channel.
|
||||||
This means that all variables will have their initial record, with the chIdx set to 'any',
|
This means that all variables will have their initial record, with the chIdx set to 'any',
|
||||||
and then they may also have further variable records will for each explicit
|
and then they may also have further variable records for each explicit
|
||||||
channel number. The complete list of channelized variable record
|
channel number. The complete list of channelized variable record
|
||||||
is kept, in channel order, using the 'ch_link' links with the base of the list
|
is kept, in channel order, using the 'ch_link' links with the base of the list
|
||||||
on the 'any' record.
|
on the 'any' record.
|
||||||
|
|
||||||
3. Apply the variable values defined in the instance 'args' record.
|
3. Apply the variable values defined in a instance 'args' record.
|
||||||
This application is treated similarly to the 'class'
|
The 'args' record may have multiple sets of args.
|
||||||
preset. If the variable value is presented in a list then
|
If the preset instance includes an 'argsLabel' value then this record
|
||||||
the value is assigned to a specific channel if the channel
|
is selected to be applied. If No 'argsLabel' is given then
|
||||||
already exists then the value is simply replaced, if the
|
the record named 'default' is selected. If there is no record
|
||||||
channel does not exist then the variable is 'channelized'.
|
named 'default' then no record is applied.
|
||||||
|
|
||||||
|
The application of the args record proceeds exactly the same as
|
||||||
|
applying a 'class' preset. If the variable value is presented in a
|
||||||
|
list then the value is assigned to a specific channel. If the channel
|
||||||
|
already exists then the value is simply replaced. If the channel does
|
||||||
|
not exist then the variable is 'channelized'.
|
||||||
|
|
||||||
4. The varaibles listed in the 'in' list of the instance cfg.
|
4. The varaibles listed in the 'in' list of the instance cfg.
|
||||||
are connected to their source variables.
|
are connected to their source variables.
|
||||||
@ -518,6 +529,645 @@ before registering the variable.
|
|||||||
6. The internal variable id map is created to implement fast
|
6. The internal variable id map is created to implement fast
|
||||||
access to registered variables.
|
access to registered variables.
|
||||||
|
|
||||||
|
7. The
|
||||||
|
|
||||||
|
# Notes on 'poly' and 'mult':
|
||||||
|
|
||||||
|
The 'in' statement is formed by a list of _Connect Expressions_ :
|
||||||
|
|
||||||
|
`<input_var>:<source_inst.source_var>`
|
||||||
|
|
||||||
|
There are three forms of connect expressions:
|
||||||
|
|
||||||
|
1. Simple Connect Expression: Both the input and source labels
|
||||||
|
identify vars in the input and source instance.
|
||||||
|
|
||||||
|
2. Manual Mult Connect Expression: The input identifer ends with an
|
||||||
|
integer. This expression indicates that an input var will be
|
||||||
|
instantiated and connected to the source var. The integer indicates
|
||||||
|
the suffix (sfx) id of the input var. e.g. `in0:osc.out`,`in1:filt.out`.
|
||||||
|
|
||||||
|
3. PolyMult Connect Expression: The source identifier has an
|
||||||
|
underscore suffix. This form indicates that there will one instance of
|
||||||
|
this var for each poly instance that the source var instances is
|
||||||
|
contained by. e.g. `in:osc_.out` If `osc` is contained by an order 3
|
||||||
|
poly then statement will create and connect three instances of `in` -
|
||||||
|
`in0:osc0.out`,`in1:osc1.out` and `in2:osc2.out`.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- For an input variable to be used in either of the 'Manual' or 'PolyMult'
|
||||||
|
forms the var class desc must have the 'mult' attribute.
|
||||||
|
|
||||||
|
- If any var has an integer suffix then this is converted to it's sfx id.
|
||||||
|
|
||||||
|
- If the input var of a poly mult expression has an integer suffix then this is taken to be the
|
||||||
|
base sfx id for that poly connection. Other connections in the same statement will be
|
||||||
|
incremented from that base value. e.g `in3:osc_.out` becomes
|
||||||
|
`in3:osc0.out`,`in4:osc1.out` and `in5:osc2.out`.
|
||||||
|
|
||||||
|
- The first and last poly source instance can be indicated by specifying a
|
||||||
|
begin poly index and count before and after the source index underscore:
|
||||||
|
e.g. `in:osc3_3.out` becomes: `in0:osc3.out`,`in1:osc4.out` and `in2:osc5.out`.
|
||||||
|
|
||||||
|
- A similar scheme can be used to indicate particular source instance vars:
|
||||||
|
`in:osc.out1_2` becomes `in0:osc.out1`,`in1:osc.out2`
|
||||||
|
|
||||||
|
- It is a compile time error to have more than one input variable with the same sfx id.
|
||||||
|
|
||||||
|
'in' List Syntax and Semantics:
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
-------
|
||||||
|
The 'in' list has the follow syntax:
|
||||||
|
`in: { in-stmt* }`
|
||||||
|
`in-stmt` -> `in_expr`":" `src_expr`
|
||||||
|
`in-expr` -> `in-proc-id`".`in-var-id`
|
||||||
|
`src-expr` -> `src-proc-id`"."`src-var-id`
|
||||||
|
`in-var-id` -> `var-id`
|
||||||
|
`src-proc-id` -> `var-id`
|
||||||
|
`src-var-id` -> `var-id`
|
||||||
|
`var-id` -> `label` { `label-sfx` }
|
||||||
|
`label-sfx` -> { `pri-int`} {{"_"} `sec-int` }
|
||||||
|
`pri-int` -> int
|
||||||
|
`sec-int` -> int
|
||||||
|
|
||||||
|
|
||||||
|
Semantics:
|
||||||
|
----------
|
||||||
|
|
||||||
|
### `in-proc-id`
|
||||||
|
|
||||||
|
- The `in-proc-id` is only used when the in-stmt
|
||||||
|
is iterating over the in-proc sfx-id.
|
||||||
|
This precludes iterating over the in-var, as discussed below.
|
||||||
|
|
||||||
|
In this case the only useful option is to set the 'var-id` to `_`
|
||||||
|
as the in-proc is taken as the the proc which the
|
||||||
|
in-stmt belongs to.
|
||||||
|
|
||||||
|
The iterating source and/or var sfx-id are then set
|
||||||
|
to the current proc sfx-id + source `pri-int`.
|
||||||
|
|
||||||
|
|
||||||
|
### `in-var-id`
|
||||||
|
|
||||||
|
- The `label` part of the `in-var-id` must match to a
|
||||||
|
var description in the input proc class description.
|
||||||
|
|
||||||
|
- If no `label-sfx` is given then no special action
|
||||||
|
need by taken at var creation time. This var will be
|
||||||
|
created by default and later connected to the source inst/var.
|
||||||
|
|
||||||
|
|
||||||
|
- (0) If the "_" is given:
|
||||||
|
+ This is an "iterating" in-stmt where multiple
|
||||||
|
input vars will be created and connected.
|
||||||
|
|
||||||
|
+ If no `pri-int` is given then the `pri-int` defaults to 0.
|
||||||
|
|
||||||
|
+ If the `pri-int` is given then it indicates that
|
||||||
|
an instance of this var should be created where
|
||||||
|
the `pri-int` becomes the sfx-id of the var instance.
|
||||||
|
|
||||||
|
+ If `sec-int` is given then it gives the
|
||||||
|
count of input vars which will be created. The
|
||||||
|
sfx-id of each new input var begins with `pri-int`
|
||||||
|
and increments for each new var.
|
||||||
|
|
||||||
|
+ (1) If no `sec-int` is given then the `sec-int` is implied by the count
|
||||||
|
of source variables indicated in the `src-expr`.
|
||||||
|
|
||||||
|
|
||||||
|
- If "_" is not given:
|
||||||
|
+ No `sec-int` can exist without a "_".
|
||||||
|
|
||||||
|
+ If a `pri-int` is given then a single
|
||||||
|
input var is created and the `pri-int`
|
||||||
|
gives the sfx-id. This single input
|
||||||
|
var is then connected to a single src var.
|
||||||
|
|
||||||
|
+ If no `pri-int` is given
|
||||||
|
then the default var is created
|
||||||
|
with kBaseSfxId and is connected
|
||||||
|
to a single source var.
|
||||||
|
|
||||||
|
|
||||||
|
### `src-proc-id`
|
||||||
|
|
||||||
|
- The `label` part of the `src-proc-id` must match to a
|
||||||
|
previously created proc instance in the current network.
|
||||||
|
|
||||||
|
- If a `label-sfx` is given then the `pri-int` gives
|
||||||
|
the sfx-id of the first proc inst to connect to.
|
||||||
|
If no `pri-int` is given then the first sfx-id
|
||||||
|
defaults to 0.
|
||||||
|
|
||||||
|
|
||||||
|
- If "_" is given:
|
||||||
|
+ This is an "iterating" src-proc and therefore
|
||||||
|
the in-var must also be iterating. See (0)
|
||||||
|
|
||||||
|
+ If a `sec-int` is given then this gives the count of
|
||||||
|
connections across multiple proc instances with
|
||||||
|
sfx-id's beginnign with `pri-int`. Note that if
|
||||||
|
`sec-int` is given then the `in-var-id` must be
|
||||||
|
iterating and NOT specify an iteration count,
|
||||||
|
as in (1) above.
|
||||||
|
|
||||||
|
+ If no `sec-int` is given then the
|
||||||
|
`sec-int` defaults to the count of
|
||||||
|
available proc instances with the given `label`
|
||||||
|
following the source proc inst `pri-int`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- If "_" is not given then this is not an
|
||||||
|
iterating proc inst.
|
||||||
|
|
||||||
|
+ If the input var is iterating
|
||||||
|
then it must specify the iteration count or
|
||||||
|
the `src-var-id` must be iterating.
|
||||||
|
|
||||||
|
+ If the `pri-int` is given then it specifies
|
||||||
|
the sfx-id of the src-proc
|
||||||
|
|
||||||
|
+ If the `pri-int` is not given
|
||||||
|
|
||||||
|
- If the src-net is the same as the in-var net then
|
||||||
|
the sfx-id of the in-var proc is used as the src-proc sfx-id
|
||||||
|
|
||||||
|
|
||||||
|
### `src-var-id`
|
||||||
|
|
||||||
|
- The `label` part of the `in-var-id` must match to a
|
||||||
|
var description in the source proc class descriptions.
|
||||||
|
|
||||||
|
- If a `label-sfx` is given then the `pri-int` gives
|
||||||
|
the sfx-id of the first source var to connect to
|
||||||
|
on the source proc instance. If no `pri-int` is
|
||||||
|
given then the first sfx-id defaults to 0.
|
||||||
|
|
||||||
|
- If a "_" is given:
|
||||||
|
+ This is an "iterating"
|
||||||
|
source var and therefore the input var
|
||||||
|
must specifiy an iterating connection and
|
||||||
|
the source proc inst must not specify an iterating
|
||||||
|
connection. See (0) above.
|
||||||
|
|
||||||
|
+ If a `sec-int` is given then this gives the count of
|
||||||
|
connections across multiple source vars with
|
||||||
|
sfx-id's beginnign with `pri-int`. Note that if
|
||||||
|
`sec-int` is given then the `in-var-id` must be
|
||||||
|
iterating and NOT specify an iteration count,
|
||||||
|
as in (1) above.
|
||||||
|
|
||||||
|
|
||||||
|
+ If `sec-int` is not given
|
||||||
|
then the `sec-int` defaults to the count of
|
||||||
|
available source vars with the given `label`
|
||||||
|
following the source var `pri-int`.
|
||||||
|
|
||||||
|
- If "_" is not given then this is not an
|
||||||
|
iterating source var. If the input var is iterating
|
||||||
|
then it must specify the iteration count or
|
||||||
|
the `src-proc-id` must be iterating.
|
||||||
|
|
||||||
|
|
||||||
|
### Notes:
|
||||||
|
|
||||||
|
- If the `in-var-id` is iterating but neither `src-proc-id`
|
||||||
|
or `src-var-id` are iterating then the `in-var-id` must
|
||||||
|
specify the iteration count and the connection will be
|
||||||
|
made to exactly one source var on the source proc inst.
|
||||||
|
|
||||||
|
- If `in-var-id` is iterating then the iterations count
|
||||||
|
must come from exactly one place:
|
||||||
|
+ the input var `sec-int`
|
||||||
|
+ the source proc `sec-int`
|
||||||
|
+ the source var `sec-int`
|
||||||
|
|
||||||
|
This means that only one literal iter count can be
|
||||||
|
given per `in-stmt`. It is a syntax error if
|
||||||
|
more than one literal iter counts are given.
|
||||||
|
|
||||||
|
- Use cases
|
||||||
|
+ connect one input to one source
|
||||||
|
+ connect multiple inputs to the same var on multiple procs
|
||||||
|
+ connect multiple inputs to multiple vars on one proc
|
||||||
|
+ connect multiple inputs to one var on one proc
|
||||||
|
|
||||||
|
|
||||||
|
### in-stmt Examples:
|
||||||
|
|
||||||
|
`in:sproc.svar` Connect the local variable `in` to the source variable `sproc.svar`.
|
||||||
|
|
||||||
|
`in0:sproc.svar` Create variables `in0` and connect to `sproc.svar`.
|
||||||
|
|
||||||
|
`in_2:sproc.svar` Create variables `in0` and `in1` and connect both new variables to `sproc.svar`.
|
||||||
|
|
||||||
|
`in_:sproc.svar0_2` Create variables `in0` and `in1` and connect them to `sproc.svar0` and `sproc.svar1`.
|
||||||
|
|
||||||
|
`in3_3:sproc.svar` Create variables `in3`,`in4` and `in5` and connect them all to `sproc.svar`.
|
||||||
|
|
||||||
|
`in_:sproc.svar1_2` Create variables `in0`,`in1` and connect them to `sproc.svar1` and `sproc.svar2`.
|
||||||
|
|
||||||
|
`in1_2:sproc.svar3_` Create variables `in1`,`in2` and connect them to `sproc.svar3` and `sproc.svar4`.
|
||||||
|
|
||||||
|
`in_:sproc.svar_` Create vars `in0 ... n-1` where `n` is count of vars on `sproc` with the label `svar`.
|
||||||
|
`n` is called the 'mult-count' of `svar`. The new variables `in0 ... n-1` are also connected to `sproc.svar0 ... n-1`.
|
||||||
|
|
||||||
|
`in_:sproc_.svar` Create vars `in0 ... n` where `n` is determineed by the count of procs named `sproc`.
|
||||||
|
`n` is called the 'poly-count' of `sproc`. The new variables `in0 ... n-1` are also connected to `sproc.svar0 ... n-1`
|
||||||
|
|
||||||
|
If an underscore precedes the in-var then this implies that the connection is being
|
||||||
|
made from a poly context.
|
||||||
|
|
||||||
|
`foo : { ... in:{ _.in:sproc.svar_ } ... } ` This example shows an excerpt from the network
|
||||||
|
definition of proc `foo` which is assumed to be a poly proc (there are multiple procs named 'foo' in this network).
|
||||||
|
This connection iterates across the procs `foo:0 ... foo:n-1` connecting the
|
||||||
|
the local variable 'in' to `sproc.svar0 ... n-1`. Where `n` is the poly count of `foo`.
|
||||||
|
|
||||||
|
`foo : { ... in:{ 1_3.in:sproc.svar_ } ... }` Connect `foo:1-in:0` to `sproc:svar0` and `foo:2-in:0` to `sproc:svar1`.
|
||||||
|
|
||||||
|
`foo : { ... in:{ 1_3.in:sproc_.svar } ... }` Connect `foo:1-in:0` to `sproc0:svar0` and `foo:2-in:0` to `sproc1:svar`.
|
||||||
|
|
||||||
|
#### in-stmt Anti-Examples
|
||||||
|
|
||||||
|
`in_:sproc_.svar_` This is illegal because there is no way to determine how many `in` variables should be created.
|
||||||
|
|
||||||
|
`in:sproc.svar_` This is illegal because it suggests that multiple sources should be connected to a single input variable.
|
||||||
|
|
||||||
|
`in:sproc_.svar` This is illegal because it suggests that multiple sources should be connected to a single input variable.
|
||||||
|
|
||||||
|
`_.in_:sproc.svar` This is illegal because it suggests simultaneously iterating across both the local proc and var.
|
||||||
|
This would be possible if there was a way to separate how the two separate iterations should be distributed
|
||||||
|
to the source. To make this legal would require an additional special character to show how to apply the poly
|
||||||
|
iteration and/or var iteration to the source. (e.g. `_.in_:sproc*.svar_`)
|
||||||
|
|
||||||
|
### out-stmt Examples:
|
||||||
|
|
||||||
|
`out:iproc.ivar` Connect the local source variable `out` to the input variable `iproc:ivar`.
|
||||||
|
|
||||||
|
`out:iproc.ivar_` Connect the local source variable `out` to the input variables `iproc:ivar0` and `iproc:ivar1`.
|
||||||
|
|
||||||
|
`out_:iproc.ivar_` Connect the local souce variables `out0 ... out n-1` to the input variables `iproc:ivar0 ... iproc:ivar n-1`
|
||||||
|
where `n` is the mult count of the `out`.
|
||||||
|
|
||||||
|
`out_:iproc_.ivar` Connect the local souce variables `out0 ... out n-1` to the input variables `iproc0:ivar ... iproc n-1:ivar`
|
||||||
|
where `n` is the mult count of the `out`.
|
||||||
|
|
||||||
|
|
||||||
|
`_.out:iproc.ivar_` Connect the local source variables `foo0:out`, `foo n-1:out` to the input variables `iproc:ivar0`, `iproc:ivar n-1`.
|
||||||
|
where `n` is the poly count of `foo`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Var Updates and Preset Application
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Variable addresses are formed from the following parameters:
|
||||||
|
`(<proc_label><proc_label_sfx_id>)*,var_label,var_label_sfx_id, ch_idx`
|
||||||
|
|
||||||
|
In the cases of poly procs (procs with public internal networks) it
|
||||||
|
may not always be possible to know the `<proc_label_sfx_id>` without
|
||||||
|
asking for it at runtime. For example for the cross-fader control the
|
||||||
|
application must ask for the `<proc_label_sfx_id>` current or next
|
||||||
|
poly channel depending on which one it is targetting.
|
||||||
|
|
||||||
|
It is notable that any proc with an internal network has
|
||||||
|
to solve this problem. The problem is especially acute
|
||||||
|
for proc's which change the 'current' poly channel at runtime.
|
||||||
|
|
||||||
|
The alternative is to include the concept of special values
|
||||||
|
in the address (e.g. kInvalidIdx means the application isn't
|
||||||
|
sure and the network should decide how to resolve the address)
|
||||||
|
The problem with this is that the information
|
||||||
|
to make that decision may require more information than
|
||||||
|
just a simple 'special value' can encode. It also means
|
||||||
|
complicating the var set/get pipeline with 'escape' routines.
|
||||||
|
|
||||||
|
There are at least two known use cases which need to address
|
||||||
|
this issue:
|
||||||
|
1. The cross-fader: The application may wish to address
|
||||||
|
updates to the current or next poly channel but this
|
||||||
|
channel can't be determined until runtime.
|
||||||
|
|
||||||
|
- The application asks for the current or next `proc_label_sfx_id`
|
||||||
|
at runtime depending on what its interested in doing,
|
||||||
|
and sets the update address accordingly.
|
||||||
|
|
||||||
|
|
||||||
|
- Two interface objects are setup as sources for the `xfade_ctl`
|
||||||
|
object. The address of each of these objects can be
|
||||||
|
determined prior to runtime. The application then simply addresses
|
||||||
|
the object corresponding to method (direct vs deferred) it requires.
|
||||||
|
This solution is particularly appealing because it means that
|
||||||
|
presets may be completely resolved to their potential
|
||||||
|
target procs (there would be up to 'poly-count' potential targets)
|
||||||
|
prior to runtime.
|
||||||
|
|
||||||
|
As it stands now the problem with this approach is that it
|
||||||
|
does not allow for the message to be resolved to its final
|
||||||
|
destination. If the message is addressed to a proxy proc
|
||||||
|
then that proxy must mimic all the vars on the object which
|
||||||
|
it is providing an interface for. (This is actually possible
|
||||||
|
and may be a viable solution???)
|
||||||
|
|
||||||
|
One solution to this is to create a data type which is an
|
||||||
|
address/value packet. The packet would then be directed
|
||||||
|
to a router which would in turn use the value to forward
|
||||||
|
the packet to the next destination. Each router that the
|
||||||
|
packet passed through would strip off a value and
|
||||||
|
pass along the message. This is sensible since the 'value'
|
||||||
|
associated with a router is in fact another address.
|
||||||
|
|
||||||
|
2. The polyphonic sampler:
|
||||||
|
|
||||||
|
- How can voices be addressed once they are started?
|
||||||
|
+ A given note is started - how do we later address that note to turn it off?
|
||||||
|
Answer: MIDI pitch and channel - only one note may be sounding on a given MIDI pitch and channel at any one time.
|
||||||
|
|
||||||
|
- Extending ths idea to the xfader: There are two channels: current and deferred,
|
||||||
|
but which are redirected to point to 2 of the 3 physical channels .... this would
|
||||||
|
require the idea of 'redirected' networks, i.e. networks whose proc lists were
|
||||||
|
really pointers to the physical procs.
|
||||||
|
- sd_poly maintains the physical networks as it is currently implemnted.
|
||||||
|
- xfade_ctl maintains the redirected networks - requests for proc/var addresses
|
||||||
|
on the redirected networks will naturally resolve to physical networks.
|
||||||
|
|
||||||
|
- Required modifications:
|
||||||
|
+ variable getters and setters must use a variable args scheme specify the var address:
|
||||||
|
`(proc-name,proc-sfx-id)*, var-name,var-sfx-id`
|
||||||
|
Example: `xfad_ctl,0,pva,1,wnd_len,0,0`
|
||||||
|
- The first 0 is known because there is only one `xfad_ctl`.
|
||||||
|
- The 1 indicates the 'deferred' channel.
|
||||||
|
- The second 0 is known because there is only one `wnd_len` per `pva`.
|
||||||
|
- The third 0 indicates the channel index of the var.
|
||||||
|
|
||||||
|
+ the address resolver must then recognize how to follow internal networks
|
||||||
|
|
||||||
|
+ Networks must be maintained as lists of pointers to procs
|
||||||
|
rather than a linked list of physical pointers.
|
||||||
|
|
||||||
|
+ `xfade_ctl` must be instantiated after `sd_poly` and be able
|
||||||
|
to access the internal network built by `sd_poly`.
|
||||||
|
|
||||||
|
|
||||||
|
Generalizing the Addressing
|
||||||
|
---------------------------
|
||||||
|
Change the set/get interface to include a list of (proc-label,proc-sfx-id)
|
||||||
|
to determine the address of the var.
|
||||||
|
|
||||||
|
Note that this still requires knowing the final address in advance.
|
||||||
|
In general a router will not know how to resolve a msg to the
|
||||||
|
next destination without having a final address.
|
||||||
|
In otherwords setting 'proc-sfx-id' to kInvalidId is not
|
||||||
|
resolvable without more information.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### TODO:
|
||||||
|
|
||||||
|
- Check for illegal variable names in class descriptions. (no periods, trailing digits, or trailing underscores)
|
||||||
|
- Check for unknown fields where the syntax clearly specifies only certain options.
|
||||||
|
|
||||||
|
- Class presets cannot address 'mult' variables (maybe this is ok since 'mult' variables are generally connected to a source.).
|
||||||
|
|
||||||
|
- Documentation w/ examples.
|
||||||
|
+ Write the rules for each implementing member function.
|
||||||
|
|
||||||
|
- value() should return a special return-code value to indicate that the
|
||||||
|
value should not be updated and distinguish it from an error code - which should stop the system.
|
||||||
|
|
||||||
|
- flow classes and variable should have a consistent naming style: camelCase or snake_case.
|
||||||
|
|
||||||
|
- String assignment is allocating memory:
|
||||||
|
See: `rc_t _val_set( value_t* val, const char* v ) cwFlowTypes.cpp line:464.`
|
||||||
|
|
||||||
|
|
||||||
|
- Variable attributes should be meaningful. e.g. src,src_opt,mult,init, ....
|
||||||
|
Should we check for 'src' or 'mult' attribute on var's?
|
||||||
|
(In other words: Enforce var attributes.)
|
||||||
|
|
||||||
|
- Reduce runtime overhead for var get/set operations.
|
||||||
|
|
||||||
|
- Implement matrix types.
|
||||||
|
|
||||||
|
- Should the `object_t` be used in place of `value_t`?
|
||||||
|
|
||||||
|
- Allow min/max limits on numeric variables.
|
||||||
|
|
||||||
|
- log:
|
||||||
|
+ should print the values for all channels - right now it is only
|
||||||
|
printing the values for kAnyChIdx
|
||||||
|
+ log should print values for abuf (mean,max), fbuf (mean,max) mag, mbuf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- DONE: Compile presets: at load time the presets should be resolved
|
||||||
|
to the proc and vars to which they will be assigned.
|
||||||
|
|
||||||
|
|
||||||
|
- DONE: (We are not removing the kAnyChIdx)
|
||||||
|
Should the var's with multiple channels remove the 'kAnyChIdx'?
|
||||||
|
This may be a good idea because 'kAnyChIdx' will in general not be used
|
||||||
|
if a var has been channelized - and yet it is possible for another
|
||||||
|
var to connect to it as a source ... which doesn't provoke an error
|
||||||
|
but would almost certainly not do what the user expects.
|
||||||
|
Note that the kAnyChIdx provides an easy way to set all of the channels
|
||||||
|
of a variable to the same value.
|
||||||
|
|
||||||
|
|
||||||
|
- DONE: verifiy that all proc variables values have a valid type - (i.e. (type & typeMask) != 0)
|
||||||
|
when the proc instance create is complete. This checks that both the type is assigned and
|
||||||
|
a valid value has been assigned - since the type is assigned the first time a value is set.
|
||||||
|
|
||||||
|
- DONE: 'poly' should be implemented as a proc-inst with an internal network - but the
|
||||||
|
elements of the network should be visible outside of it.
|
||||||
|
|
||||||
|
- DONE: 'sub' should be implemented as proc-inst with an internal network, but the
|
||||||
|
elements of the network should not be visible outside of it. Instead it should
|
||||||
|
include the idea of input and output ports which act as proxies to the physical
|
||||||
|
ports of the internal elements.
|
||||||
|
|
||||||
|
- DONE: 'poly' and 'sub' should be arbitrarily nestable.
|
||||||
|
|
||||||
|
- DONE: Allow multiple types on an input.
|
||||||
|
For example 'adder' should have a single input
|
||||||
|
which can by any numeric type.
|
||||||
|
|
||||||
|
|
||||||
|
- DONE: Make a standard way to turn on output printing from any port on any instance
|
||||||
|
This might be a better approach to logging than having a 'printer' object.
|
||||||
|
Add proc instance field: `log:{ var_label_0:0, var_label_1:0 } `
|
||||||
|
|
||||||
|
Next:
|
||||||
|
|
||||||
|
- Complete subnets:
|
||||||
|
+ Subnets should have presets written in terms of the subnet vars rather than the network vars
|
||||||
|
or the value application needs to follow the internal variable src_var back to the proxy var.
|
||||||
|
|
||||||
|
+ DONE: write a paragraph in the flow_doc.md about overall approach taken to subnet implementation.
|
||||||
|
|
||||||
|
+ DONE: subnet var desc's should be the same as non+subnet vars but also include the 'proxy' field.
|
||||||
|
In particular they should get default values.
|
||||||
|
If a var desc is part of a subnet then it must have a proxy.
|
||||||
|
The output variables of var desc's must have the 'out' attribute
|
||||||
|
|
||||||
|
|
||||||
|
+ DONE: improve the subnet creating code by using consistent naming + use proxy or wrap but not both
|
||||||
|
|
||||||
|
+ DONE: improve code comments on subnet creation
|
||||||
|
|
||||||
|
- Audio inputs should be able to be initialized with a channel count and srate without actually connecting an input.
|
||||||
|
This will allow feedback connections to be attached to them at a later stage of the network
|
||||||
|
instantiation.
|
||||||
|
- Remove the multiple 'args' thing and and 'argsLabel'. 'args' should be a simple set of arg's.
|
||||||
|
- Implement subnet preset application.
|
||||||
|
- Implement the var attributes and attribute checking.
|
||||||
|
- Implement dynamic loading of procs.
|
||||||
|
- Implement a debug mode to aid in building networks and subnets (or is logging good enough)
|
||||||
|
- Implement multi-field messages.
|
||||||
|
- Look more closely at the way of identify an in-stmt src-net or a out-stmt in-net.
|
||||||
|
It's not clear there is a difference between specifying `_` and the default behaviour.
|
||||||
|
Is there a way to tell it to search the entire network from the root? Isn't that
|
||||||
|
what '_' is supposed to do.
|
||||||
|
|
||||||
|
- DONE: Implement feedback
|
||||||
|
|
||||||
|
- DONE: Implement the ability to set backward connections - from late to early proc's.
|
||||||
|
This can be done by implementing the same process as 'in_stmt' but in a separate
|
||||||
|
'out_stmt'. The difficulty is that it prevents doing some checks until the network
|
||||||
|
is completely specified. For example if audio inputs can accept connections from
|
||||||
|
later proc's then they will not have all of their inputs when they are instantiated.
|
||||||
|
One way around this is to instantiate them with an initial set of inputs but then
|
||||||
|
allow those inputs to be replaced by a later connection.
|
||||||
|
|
||||||
|
BUGS:
|
||||||
|
- The counter modulo mode is not working as expected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Host Environments:
|
||||||
|
------------------
|
||||||
|
- CLI, no GUI, no I/O, non-real-time only.
|
||||||
|
- CLI, no GUI, w/ I/O and real-time
|
||||||
|
- GUI, with configurable control panels
|
||||||
|
|
||||||
|
|
||||||
|
- DONE: Implement 'preset' proc. This will involve implementing the 'cfg' datatype.
|
||||||
|
|
||||||
|
- DONE: Finish the 'poly' frawework. We are making 'mult' var's, but do any of the procs explicitly deal with them?
|
||||||
|
|
||||||
|
- DONE: Turn on variable 'broadcast'. Why was it turned off? ... maybe multiple updates?
|
||||||
|
|
||||||
|
- DONE: There is no way for a proc in a poly context to use it's poly channel number to
|
||||||
|
select a mult variable. For example in an osc in a poly has no way to select
|
||||||
|
the frequency of the osc by conneting to a non-poly proc - like a list.
|
||||||
|
Consider:
|
||||||
|
1. Use a difference 'in' statememt (e.g. 'poly-in' but the
|
||||||
|
same syntax used for connecting 'mult' variables.)
|
||||||
|
2. Include the proc name in the 'in' var to indicate a poly index is being iterated
|
||||||
|
e.g. `lfo: { class:sine_tone, in:{ osc_.dc:list.value_ } }`
|
||||||
|
|
||||||
|
- DONE: Fix up the coding language - change the use of `instance_t` to `proc_t` and `inst` to `proc`, change use of `ctx` in cwFlowProc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Prior to executing the custom constructor the values are assigned to the
|
||||||
|
variables as follows:
|
||||||
|
1. Default value as defined by the class are applied when the variable is created.
|
||||||
|
2. The proc instance 'preset' class preset is applied.
|
||||||
|
3. The proc instance 'args' values are applied.
|
||||||
|
|
||||||
|
During this stage of processing preset values may be given for
|
||||||
|
variables that do not yet exist. This will commonly occur when a
|
||||||
|
variable has multiple channels that will not be created until the
|
||||||
|
custom constructor is run. For these cases the variable will be
|
||||||
|
pre-emptively created and the preset value will be applied.
|
||||||
|
|
||||||
|
This approach has the advantage of communicating network information
|
||||||
|
to the proc constructor from the network configuration - thereby
|
||||||
|
allowing the network programmer to influence the configuration of the
|
||||||
|
proc. instance.
|
||||||
|
|
||||||
|
|
||||||
|
DONE: After the network is fully instantiated the network and class presets
|
||||||
|
are compiled. At this point all preset values must be resolvable to
|
||||||
|
an actual proc variable. A warning is issued for presets with values
|
||||||
|
that cannot be resolved and they are disabled. The primary reason
|
||||||
|
that a preset might not be resolvable is by targetting a variable
|
||||||
|
channel that does not exist.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- How much of the proc initialization implementation can use the preset compile/apply code?
|
||||||
|
- DONE: All cfg to value conversion should go through `cfg_to_value()`.
|
||||||
|
|
||||||
|
|
||||||
|
Names:
|
||||||
|
ixon -
|
||||||
|
hoot
|
||||||
|
caw, screech, warble, coo, peep, hoot, gobble, quack, honk, whistle, tweet, cheep, chirrup, trill, squawk, seet,
|
||||||
|
cluck,cackle,clack
|
||||||
|
cock-a-dooodle-doo
|
||||||
|
song,tune,aria
|
||||||
|
|
||||||
|
|
||||||
|
caw by example:
|
||||||
|
0. DONE: Add log object.
|
||||||
|
DONE: Add initial network preset selection system parameter.
|
||||||
|
|
||||||
|
1. sine->af
|
||||||
|
in-stmt
|
||||||
|
|
||||||
|
2. sine->af with network preset
|
||||||
|
topics:preset, class info
|
||||||
|
|
||||||
|
3. number,timer,counter,list,log
|
||||||
|
topics: log, data types, system parameters
|
||||||
|
|
||||||
|
4. sine->delay->mixer->af
|
||||||
|
-------->
|
||||||
|
topics: mult vars, system parameters
|
||||||
|
|
||||||
|
5. topic: modulate sine with sine
|
||||||
|
|
||||||
|
6. topic: modulate sine with sine and timed preset change.
|
||||||
|
|
||||||
|
7. topic: iterating input stmt 0 - connect multiple inputs to a single source
|
||||||
|
|
||||||
|
8. topic: iterating input stmt 1 - multiple inputs to multiple sources
|
||||||
|
|
||||||
|
9. topic: iterating input stmt 2 - two ranges
|
||||||
|
|
||||||
|
12. topic: poly
|
||||||
|
|
||||||
|
13. topic: poly w/iterating input stmt
|
||||||
|
|
||||||
|
14. topic: poly w/ xfade ctl and presets
|
||||||
|
|
||||||
|
15. topic: msg feedback
|
||||||
|
|
||||||
|
16. topic: audio feedback
|
||||||
|
|
||||||
|
17. topic: subnets
|
||||||
|
|
||||||
|
18. topic: subnet with presets
|
||||||
|
|
||||||
|
19. topic: presets w/ sfx id's
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwTextBuf.h"
|
#include "cwTextBuf.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwAudioDevice.h"
|
#include "cwAudioDevice.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwTextBuf.h"
|
#include "cwTextBuf.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwTextBuf.h"
|
#include "cwTextBuf.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwB23Tree.h"
|
#include "cwB23Tree.h"
|
||||||
|
@ -13,16 +13,32 @@ namespace cw
|
|||||||
nanosleep(ts,NULL);
|
nanosleep(ts,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const idLabelPair_t* _idToSlot( const idLabelPair_t* array, unsigned id, unsigned eolId )
|
||||||
|
{
|
||||||
|
const idLabelPair_t* p = array;
|
||||||
|
for(; p->id != eolId; ++p)
|
||||||
|
if( p->id == id )
|
||||||
|
break;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char* cw::idToLabelNull( const idLabelPair_t* array, unsigned id, unsigned eolId )
|
||||||
|
{
|
||||||
|
const idLabelPair_t* p = _idToSlot(array,id,eolId);
|
||||||
|
|
||||||
|
return p->id == eolId ? nullptr : p->label;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cw::idToLabel( const idLabelPair_t* array, unsigned id, unsigned eolId )
|
const char* cw::idToLabel( const idLabelPair_t* array, unsigned id, unsigned eolId )
|
||||||
{
|
{
|
||||||
const idLabelPair_t* p = array;
|
const idLabelPair_t* p = _idToSlot(array,id,eolId);
|
||||||
for(; p->id != eolId; ++p)
|
|
||||||
if( p->id == id )
|
|
||||||
return p->label;
|
|
||||||
|
|
||||||
return nullptr;
|
return p->label;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned cw::labelToId( const idLabelPair_t* array, const char* label, unsigned eolId )
|
unsigned cw::labelToId( const idLabelPair_t* array, const char* label, unsigned eolId )
|
||||||
@ -31,16 +47,12 @@ unsigned cw::labelToId( const idLabelPair_t* array, const char* label, unsigned
|
|||||||
|
|
||||||
if( label != nullptr )
|
if( label != nullptr )
|
||||||
for(; p->id != eolId; ++p)
|
for(; p->id != eolId; ++p)
|
||||||
if( std::strcmp(label,p->label) == 0 )
|
if( p->label != nullptr && std::strcmp(label,p->label) == 0 )
|
||||||
return p->id;
|
return p->id;
|
||||||
|
|
||||||
return eolId;
|
return eolId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cw::sleepSec( unsigned secs )
|
void cw::sleepSec( unsigned secs )
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
@ -138,8 +138,8 @@ namespace cw
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
#define cwAssert(C) while(1){ if(!(C)){ cwLogFatal(kAssertFailRC,"Assert failed on condition:%s",#C ); } break; }
|
#define cwAssert(C) while(1){ if(!(C)) { cwLogFatal(kAssertFailRC,"Assert failed on condition:%s",#C ); } break; }
|
||||||
|
#define cwRuntimeCheck(C) while(1){ if(!(C)) { rc=cwLogError(kAssertFailRC,"Runtime error check failed on condition:%s",#C); goto errLabel; } break; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -160,6 +160,9 @@ namespace cw
|
|||||||
} idLabelPair_t;
|
} idLabelPair_t;
|
||||||
|
|
||||||
// Return nullptr if id is not found.
|
// Return nullptr if id is not found.
|
||||||
|
const char* idToLabelNull( const idLabelPair_t* array, unsigned id, unsigned eolId );
|
||||||
|
|
||||||
|
// Returns label in 'eolId' slot if id is not found.
|
||||||
const char* idToLabel( const idLabelPair_t* array, unsigned id, unsigned eolId );
|
const char* idToLabel( const idLabelPair_t* array, unsigned id, unsigned eolId );
|
||||||
|
|
||||||
// Returns eolId if the id is not found.
|
// Returns eolId if the id is not found.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwUtility.h"
|
#include "cwUtility.h"
|
||||||
#include "cwMath.h"
|
#include "cwMath.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
@ -21,9 +22,9 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace compressor
|
namespace compressor
|
||||||
{
|
{
|
||||||
void _ms_to_samples( obj_t*p, real_t ms, unsigned& outRef )
|
void _ms_to_samples( obj_t*p, ftime_t ms, unsigned& outRef )
|
||||||
{
|
{
|
||||||
outRef = std::max((real_t)1,(real_t)floor(ms * p->srate / 1000.0));
|
outRef = std::max(1u,(unsigned)floor(ms * p->srate / 1000.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,7 +34,7 @@ namespace cw
|
|||||||
// compressor
|
// compressor
|
||||||
//
|
//
|
||||||
|
|
||||||
cw::rc_t cw::dsp::compressor::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio_num, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl )
|
cw::rc_t cw::dsp::compressor::create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t inGain, ftime_t rmsWndMaxMs, ftime_t rmsWndMs, coeff_t threshDb, coeff_t ratio_num, ftime_t atkMs, ftime_t rlsMs, coeff_t outGain, bool bypassFl )
|
||||||
{
|
{
|
||||||
p = mem::allocZ<obj_t>();
|
p = mem::allocZ<obj_t>();
|
||||||
|
|
||||||
@ -105,8 +106,8 @@ cw::rc_t cw::dsp::compressor::exec( obj_t* p, const sample_t* x, sample_t* y, un
|
|||||||
p->rmsWnd[ p->rmsWndIdx ] = vop::rms(xx, n); // calc and store signal RMS
|
p->rmsWnd[ p->rmsWndIdx ] = vop::rms(xx, n); // calc and store signal RMS
|
||||||
p->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer
|
p->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer
|
||||||
|
|
||||||
real_t rmsLin = vop::mean(p->rmsWnd,p->rmsWndCnt); // calc avg RMS
|
coeff_t rmsLin = vop::mean(p->rmsWnd,p->rmsWndCnt); // calc avg RMS
|
||||||
real_t rmsDb = std::max(-100.0,20 * log10(std::max((real_t)0.00001,rmsLin))); // convert avg RMS to dB
|
coeff_t rmsDb = std::max(-100.0,20 * log10(std::max((coeff_t)0.00001,rmsLin))); // convert avg RMS to dB
|
||||||
rmsDb += 100.0;
|
rmsDb += 100.0;
|
||||||
|
|
||||||
// if the compressor is bypassed
|
// if the compressor is bypassed
|
||||||
@ -147,17 +148,17 @@ cw::rc_t cw::dsp::compressor::exec( obj_t* p, const sample_t* x, sample_t* y, un
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cw::dsp::compressor::set_attack_ms( obj_t* p, real_t ms )
|
void cw::dsp::compressor::set_attack_ms( obj_t* p, ftime_t ms )
|
||||||
{
|
{
|
||||||
_ms_to_samples(p,ms,p->atkSmp);
|
_ms_to_samples(p,ms,p->atkSmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cw::dsp::compressor::set_release_ms( obj_t* p, real_t ms )
|
void cw::dsp::compressor::set_release_ms( obj_t* p, ftime_t ms )
|
||||||
{
|
{
|
||||||
_ms_to_samples(p,ms,p->rlsSmp);
|
_ms_to_samples(p,ms,p->rlsSmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms )
|
void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, ftime_t ms )
|
||||||
{
|
{
|
||||||
p->rmsWndCnt = std::max((unsigned)1,(unsigned)floor(ms * p->srate / (1000.0 * p->procSmpCnt)));
|
p->rmsWndCnt = std::max((unsigned)1,(unsigned)floor(ms * p->srate / (1000.0 * p->procSmpCnt)));
|
||||||
|
|
||||||
@ -170,7 +171,7 @@ void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms )
|
|||||||
// Limiter
|
// Limiter
|
||||||
//
|
//
|
||||||
|
|
||||||
cw::rc_t cw::dsp::limiter::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t thresh, real_t igain, real_t ogain, bool bypassFl )
|
cw::rc_t cw::dsp::limiter::create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t thresh, coeff_t igain, coeff_t ogain, bool bypassFl )
|
||||||
{
|
{
|
||||||
p = mem::allocZ<obj_t>();
|
p = mem::allocZ<obj_t>();
|
||||||
|
|
||||||
@ -196,7 +197,7 @@ cw::rc_t cw::dsp::limiter::exec( obj_t* p, const sample_t* x, sample_t* y, unsig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
real_t T = p->thresh * p->ogain;
|
coeff_t T = p->thresh * p->ogain;
|
||||||
|
|
||||||
for(unsigned i=0; i<n; ++i)
|
for(unsigned i=0; i<n; ++i)
|
||||||
{
|
{
|
||||||
@ -227,7 +228,7 @@ cw::rc_t cw::dsp::limiter::exec( obj_t* p, const sample_t* x, sample_t* y, unsig
|
|||||||
// dc-filter
|
// dc-filter
|
||||||
//
|
//
|
||||||
|
|
||||||
cw::rc_t cw::dsp::dc_filter::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t gain, bool bypassFl )
|
cw::rc_t cw::dsp::dc_filter::create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t gain, bool bypassFl )
|
||||||
{
|
{
|
||||||
p = mem::allocZ<obj_t>();
|
p = mem::allocZ<obj_t>();
|
||||||
|
|
||||||
@ -255,12 +256,12 @@ cw::rc_t cw::dsp::dc_filter::exec( obj_t* p, const sample_t* x, sample_t* y, uns
|
|||||||
if( p->bypassFl )
|
if( p->bypassFl )
|
||||||
vop::copy(y,x,n);
|
vop::copy(y,x,n);
|
||||||
else
|
else
|
||||||
vop::filter<sample_t,real_t>(y,n,x,n,p->b0, p->b, p->a, p->d, 1 );
|
vop::filter<sample_t,coeff_t>(y,n,x,n,p->b0, p->b, p->a, p->d, 1 );
|
||||||
|
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::dsp::dc_filter::set( obj_t* p, real_t gain, bool bypassFl )
|
cw::rc_t cw::dsp::dc_filter::set( obj_t* p, coeff_t gain, bool bypassFl )
|
||||||
{
|
{
|
||||||
p->gain = gain;
|
p->gain = gain;
|
||||||
p->bypassFl = bypassFl;
|
p->bypassFl = bypassFl;
|
||||||
@ -272,7 +273,7 @@ cw::rc_t cw::dsp::dc_filter::set( obj_t* p, real_t gain, bool bypassFl )
|
|||||||
// Recorder
|
// Recorder
|
||||||
//
|
//
|
||||||
|
|
||||||
cw::rc_t cw::dsp::recorder::create( obj_t*& pRef, real_t srate, real_t max_secs, unsigned chN )
|
cw::rc_t cw::dsp::recorder::create( obj_t*& pRef, srate_t srate, ftime_t max_secs, unsigned chN )
|
||||||
{
|
{
|
||||||
obj_t* p = mem::allocZ<obj_t>();
|
obj_t* p = mem::allocZ<obj_t>();
|
||||||
p->srate = srate;
|
p->srate = srate;
|
||||||
@ -383,7 +384,7 @@ namespace cw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::dsp::audio_meter::create( obj_t*& p, real_t srate, real_t maxWndMs, real_t wndMs, real_t peakThreshDb )
|
cw::rc_t cw::dsp::audio_meter::create( obj_t*& p, srate_t srate, ftime_t maxWndMs, ftime_t wndMs, coeff_t peakThreshDb )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
@ -475,7 +476,7 @@ void cw::dsp::audio_meter::reset( obj_t* p )
|
|||||||
p->clipCnt = 0;
|
p->clipCnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cw::dsp::audio_meter::set_window_ms( obj_t* p, real_t wndMs )
|
void cw::dsp::audio_meter::set_window_ms( obj_t* p, ftime_t wndMs )
|
||||||
{
|
{
|
||||||
unsigned wndSmpN = (unsigned)((wndMs * p->srate)/1000.0);
|
unsigned wndSmpN = (unsigned)((wndMs * p->srate)/1000.0);
|
||||||
|
|
||||||
|
@ -14,36 +14,36 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
real_t srate; // system sample rate
|
srate_t srate; // system sample rate
|
||||||
unsigned procSmpCnt; // samples per exec cycle
|
unsigned procSmpCnt; // samples per exec cycle
|
||||||
real_t inGain; // input gain
|
coeff_t inGain; // input gain
|
||||||
real_t threshDb; // threshold in dB (max:100 min:0)
|
coeff_t threshDb; // threshold in dB (max:100 min:0)
|
||||||
real_t ratio_num; // numerator of the ratio
|
coeff_t ratio_num; // numerator of the ratio
|
||||||
unsigned atkSmp; // time to reduce the signal by 10.0 db
|
unsigned atkSmp; // time to reduce the signal by 10.0 db
|
||||||
unsigned rlsSmp; // time to increase the signal by 10.0 db
|
unsigned rlsSmp; // time to increase the signal by 10.0 db
|
||||||
real_t outGain; // makeup gain
|
coeff_t outGain; // makeup gain
|
||||||
bool bypassFl; // bypass enable
|
bool bypassFl; // bypass enable
|
||||||
sample_t* rmsWnd; // rmsWnd[rmsWndAllocCnt]
|
sample_t* rmsWnd; // rmsWnd[rmsWndAllocCnt]
|
||||||
unsigned rmsWndAllocCnt; //
|
unsigned rmsWndAllocCnt; //
|
||||||
unsigned rmsWndCnt; // current RMS window size (rmsWndCnt must be <= rmsWndAllocCnt)
|
unsigned rmsWndCnt; // current RMS window size (rmsWndCnt must be <= rmsWndAllocCnt)
|
||||||
unsigned rmsWndIdx; // next RMS window input index
|
unsigned rmsWndIdx; // next RMS window input index
|
||||||
unsigned state; // env. state
|
unsigned state; // env. state
|
||||||
real_t rmsDb; // current incoming signal RMS (max:100 min:0)
|
coeff_t rmsDb; // current incoming signal RMS (max:100 min:0)
|
||||||
real_t gain; // current compressor gain
|
coeff_t gain; // current compressor gain
|
||||||
real_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs.
|
coeff_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs.
|
||||||
real_t pkDb; //
|
coeff_t pkDb; //
|
||||||
real_t accumDb; //
|
coeff_t accumDb; //
|
||||||
|
|
||||||
} obj_t;
|
} obj_t;
|
||||||
|
|
||||||
rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl );
|
rc_t create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t inGain, ftime_t rmsWndMaxMs, ftime_t rmsWndMs, coeff_t threshDb, coeff_t ratio, ftime_t atkMs, ftime_t rlsMs, coeff_t outGain, bool bypassFl );
|
||||||
rc_t destroy( obj_t*& pp );
|
rc_t destroy( obj_t*& pp );
|
||||||
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
||||||
|
|
||||||
void set_attack_ms( obj_t* p, real_t ms );
|
void set_attack_ms( obj_t* p, ftime_t ms );
|
||||||
void set_release_ms( obj_t* p, real_t ms );
|
void set_release_ms( obj_t* p, ftime_t ms );
|
||||||
void set_thresh_db( obj_t* p, real_t thresh );
|
void set_thresh_db( obj_t* p, coeff_t thresh );
|
||||||
void set_rms_wnd_ms( obj_t* p, real_t ms );
|
void set_rms_wnd_ms( obj_t* p, ftime_t ms );
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace limiter
|
namespace limiter
|
||||||
@ -51,13 +51,13 @@ namespace cw
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned procSmpCnt;
|
unsigned procSmpCnt;
|
||||||
real_t igain; // applied before thresholding
|
coeff_t igain; // applied before thresholding
|
||||||
real_t thresh; // linear (0.0-1.0) threshold.
|
coeff_t thresh; // linear (0.0-1.0) threshold.
|
||||||
real_t ogain; // applied after thresholding
|
coeff_t ogain; // applied after thresholding
|
||||||
bool bypassFl;
|
bool bypassFl;
|
||||||
} obj_t;
|
} obj_t;
|
||||||
|
|
||||||
rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t thresh, real_t igain, real_t ogain, bool bypassFl );
|
rc_t create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t thresh, coeff_t igain, coeff_t ogain, bool bypassFl );
|
||||||
rc_t destroy( obj_t*& pp );
|
rc_t destroy( obj_t*& pp );
|
||||||
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
||||||
}
|
}
|
||||||
@ -66,32 +66,32 @@ namespace cw
|
|||||||
{
|
{
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
real_t d[2]; //
|
coeff_t d[2]; //
|
||||||
real_t b[1]; //
|
coeff_t b[1]; //
|
||||||
real_t a[1]; // a[dn] feedback coeff's
|
coeff_t a[1]; // a[dn] feedback coeff's
|
||||||
real_t b0; // feedforward coeff 0
|
coeff_t b0; // feedforward coeff 0
|
||||||
bool bypassFl;
|
bool bypassFl;
|
||||||
real_t gain;
|
coeff_t gain;
|
||||||
} obj_t;
|
} obj_t;
|
||||||
|
|
||||||
rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t gain, bool bypassFl );
|
rc_t create( obj_t*& p, srate_t srate, unsigned procSmpCnt, coeff_t gain, bool bypassFl );
|
||||||
rc_t destroy( obj_t*& pp );
|
rc_t destroy( obj_t*& pp );
|
||||||
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
||||||
rc_t set( obj_t* p, real_t gain, bool bypassFl );
|
rc_t set( obj_t* p, coeff_t gain, bool bypassFl );
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace recorder
|
namespace recorder
|
||||||
{
|
{
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
real_t srate; //
|
srate_t srate; //
|
||||||
unsigned maxFrameN; //
|
unsigned maxFrameN; //
|
||||||
unsigned chN; // channel count
|
unsigned chN; // channel count
|
||||||
unsigned frameIdx; // next frame to write
|
unsigned frameIdx; // next frame to write
|
||||||
sample_t* buf; // [ [maxFrameN] [maxFrameN] ]
|
sample_t* buf; // [ [maxFrameN] [maxFrameN] ]
|
||||||
} obj_t; // ch0 ch1
|
} obj_t; // ch0 ch1
|
||||||
|
|
||||||
rc_t create( obj_t*& pRef, real_t srate, real_t max_secs, unsigned chN );
|
rc_t create( obj_t*& pRef, srate_t srate, ftime_t max_secs, unsigned chN );
|
||||||
rc_t destroy( obj_t*& pRef);
|
rc_t destroy( obj_t*& pRef);
|
||||||
|
|
||||||
rc_t exec( obj_t* p, const sample_t* buf, unsigned chN, unsigned frameN );
|
rc_t exec( obj_t* p, const sample_t* buf, unsigned chN, unsigned frameN );
|
||||||
@ -107,10 +107,10 @@ namespace cw
|
|||||||
unsigned maxWndSmpN;
|
unsigned maxWndSmpN;
|
||||||
unsigned wndSmpN;
|
unsigned wndSmpN;
|
||||||
sample_t* wndV;
|
sample_t* wndV;
|
||||||
real_t srate;
|
srate_t srate;
|
||||||
real_t peakThreshDb;
|
coeff_t peakThreshDb;
|
||||||
real_t outLin;
|
coeff_t outLin;
|
||||||
real_t outDb;
|
coeff_t outDb;
|
||||||
bool peakFl;
|
bool peakFl;
|
||||||
bool clipFl;
|
bool clipFl;
|
||||||
unsigned peakCnt;
|
unsigned peakCnt;
|
||||||
@ -118,11 +118,11 @@ namespace cw
|
|||||||
unsigned wi;
|
unsigned wi;
|
||||||
} obj_t;
|
} obj_t;
|
||||||
|
|
||||||
rc_t create( obj_t*& p, real_t srate, real_t maxWndMs, real_t wndMs, real_t peakThreshDb );
|
rc_t create( obj_t*& p, srate_t srate, ftime_t maxWndMs, ftime_t wndMs, coeff_t peakThreshDb );
|
||||||
rc_t destroy( obj_t*& pp );
|
rc_t destroy( obj_t*& pp );
|
||||||
rc_t exec( obj_t* p, const sample_t* x, unsigned n );
|
rc_t exec( obj_t* p, const sample_t* x, unsigned n );
|
||||||
void reset( obj_t* p );
|
void reset( obj_t* p );
|
||||||
void set_window_ms( obj_t* p, real_t wndMs );
|
void set_window_ms( obj_t* p, ftime_t wndMs );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace dsp
|
namespace dsp
|
||||||
{
|
{
|
||||||
typedef float real_t;
|
|
||||||
typedef float sample_t;
|
typedef float sample_t;
|
||||||
typedef float fd_real_t;
|
typedef float fd_sample_t; // Frequency domain sample - type used by magnitude,phase,real,imag. part of spectral values
|
||||||
typedef float srate_t;
|
typedef float srate_t;
|
||||||
|
typedef float coeff_t; // values that are directly applied to signals of sample_t.
|
||||||
|
typedef double ftime_t; // any time value expressed as a floating point value - could be seconds, milliseconds, etc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwObject.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwObject.h"
|
||||||
|
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
#include "cwCommonImpl.h"
|
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwString.h"
|
#include "cwString.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
@ -75,7 +79,7 @@ bool cw::filesys::isDir( const char* dir0 )
|
|||||||
{
|
{
|
||||||
// if the dir does not exist
|
// if the dir does not exist
|
||||||
if( errno == ENOENT )
|
if( errno == ENOENT )
|
||||||
return false;
|
goto errLabel;
|
||||||
|
|
||||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'",cwStringNullGuard(dir));
|
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'",cwStringNullGuard(dir));
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -106,7 +110,7 @@ bool cw::filesys::isFile( const char* fn0 )
|
|||||||
|
|
||||||
// if the file does not exist
|
// if the file does not exist
|
||||||
if( errno == ENOENT )
|
if( errno == ENOENT )
|
||||||
return false;
|
goto errLabel;
|
||||||
|
|
||||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -137,7 +141,7 @@ bool cw::filesys::isLink( const char* fn0 )
|
|||||||
{
|
{
|
||||||
// if the file does not exist
|
// if the file does not exist
|
||||||
if( errno == ENOENT )
|
if( errno == ENOENT )
|
||||||
return false;
|
goto errLabel;
|
||||||
|
|
||||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -893,3 +897,33 @@ cw::rc_t cw::filesys::makeDir( const char* dirStr )
|
|||||||
|
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::filesys::test( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
filesys::pathPart_t* pp = filesys::pathParts(__FILE__);
|
||||||
|
|
||||||
|
cwLogPrint("dir:%s",pp->dirStr);
|
||||||
|
cwLogPrint("fn: %s",pp->fnStr);
|
||||||
|
cwLogPrint("ext:%s",pp->extStr);
|
||||||
|
|
||||||
|
char* fn = filesys::makeFn( pp->dirStr, pp->fnStr, pp->extStr, nullptr );
|
||||||
|
|
||||||
|
cwLogPrint("fn: %s",fn);
|
||||||
|
|
||||||
|
mem::release(pp);
|
||||||
|
mem::release(fn);
|
||||||
|
|
||||||
|
|
||||||
|
const char myPath[] = "~/src/foo";
|
||||||
|
|
||||||
|
char* expPath = filesys::expandPath(myPath);
|
||||||
|
|
||||||
|
cwLogPrint("%s %s",myPath,expPath);
|
||||||
|
|
||||||
|
mem::release(expPath);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
@ -90,6 +90,8 @@ namespace cw
|
|||||||
char* makeVersionedDirectory(const char* recordDir, const char* recordFolder );
|
char* makeVersionedDirectory(const char* recordDir, const char* recordFolder );
|
||||||
|
|
||||||
rc_t makeDir( const char* dirStr );
|
rc_t makeDir( const char* dirStr );
|
||||||
|
|
||||||
|
rc_t test( const test::test_args_t& args );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
2141
cwFlow.cpp
2141
cwFlow.cpp
File diff suppressed because it is too large
Load Diff
46
cwFlow.h
46
cwFlow.h
@ -8,43 +8,6 @@ namespace cw
|
|||||||
|
|
||||||
typedef handle<struct flow_str> handle_t;
|
typedef handle<struct flow_str> handle_t;
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
kAudioDevTypeId,
|
|
||||||
kMidiDevTypeId,
|
|
||||||
kSerialDevTypeId,
|
|
||||||
kSocketDevTypeId
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
kInFl = 0x01,
|
|
||||||
kOutFl = 0x02
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct abuf_str;
|
|
||||||
|
|
||||||
typedef struct audio_dev_cfg_str
|
|
||||||
{
|
|
||||||
struct abuf_str* abuf; // Buffer to receive incoming or send outgoing audio for this device
|
|
||||||
// The audio_in/audio_out proc's locate and use these buffers.
|
|
||||||
} audio_dev_cfg_t;
|
|
||||||
|
|
||||||
// Generate external device record
|
|
||||||
typedef struct external_device_str
|
|
||||||
{
|
|
||||||
const char* label; // IO framework device label
|
|
||||||
unsigned ioDevId; // IO framework device id
|
|
||||||
unsigned typeId; // see ???DevTypeId above
|
|
||||||
unsigned flags; // see ???Fl above
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
audio_dev_cfg_t a; // audio devices include this additional record
|
|
||||||
} u;
|
|
||||||
|
|
||||||
} external_device_t;
|
|
||||||
|
|
||||||
|
|
||||||
void print_abuf( const struct abuf_str* abuf );
|
void print_abuf( const struct abuf_str* abuf );
|
||||||
@ -52,8 +15,10 @@ namespace cw
|
|||||||
|
|
||||||
|
|
||||||
rc_t create( handle_t& hRef,
|
rc_t create( handle_t& hRef,
|
||||||
const object_t& classCfg,
|
const object_t* classCfg,
|
||||||
const object_t& networkCfg,
|
const object_t* networkCfg,
|
||||||
|
const object_t* subnetCfg = nullptr,
|
||||||
|
const char* projDir = nullptr,
|
||||||
external_device_t* deviceA = nullptr,
|
external_device_t* deviceA = nullptr,
|
||||||
unsigned deviceN = 0);
|
unsigned deviceN = 0);
|
||||||
|
|
||||||
@ -68,8 +33,8 @@ namespace cw
|
|||||||
rc_t exec( handle_t h );
|
rc_t exec( handle_t h );
|
||||||
|
|
||||||
rc_t apply_preset( handle_t h, const char* presetLabel );
|
rc_t apply_preset( handle_t h, const char* presetLabel );
|
||||||
rc_t apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel );
|
|
||||||
rc_t apply_dual_preset( handle_t h, const char* presetLabel_0, const char* presetLabel_1, double coeff );
|
rc_t apply_dual_preset( handle_t h, const char* presetLabel_0, const char* presetLabel_1, double coeff );
|
||||||
|
rc_t apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel );
|
||||||
|
|
||||||
|
|
||||||
rc_t set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool value );
|
rc_t set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool value );
|
||||||
@ -87,7 +52,6 @@ namespace cw
|
|||||||
void print_class_list( handle_t h );
|
void print_class_list( handle_t h );
|
||||||
void print_network( handle_t h );
|
void print_network( handle_t h );
|
||||||
|
|
||||||
rc_t test( const object_t* cfg );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
@ -9,6 +10,8 @@
|
|||||||
#include "cwMtx.h"
|
#include "cwMtx.h"
|
||||||
#include "cwDspTypes.h" // real_t, sample_t
|
#include "cwDspTypes.h" // real_t, sample_t
|
||||||
#include "cwDspTransforms.h"
|
#include "cwDspTransforms.h"
|
||||||
|
#include "cwTime.h"
|
||||||
|
#include "cwMidiDecls.h"
|
||||||
#include "cwFlowDecl.h"
|
#include "cwFlowDecl.h"
|
||||||
#include "cwFlow.h"
|
#include "cwFlow.h"
|
||||||
#include "cwFlowTypes.h"
|
#include "cwFlowTypes.h"
|
||||||
@ -28,11 +31,12 @@ namespace cw
|
|||||||
kFadeOutStateId,
|
kFadeOutStateId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Each duplicated network is represented by a flow_netword_t record in flow_cross_t.netA[].
|
||||||
typedef struct flow_network_str
|
typedef struct flow_network_str
|
||||||
{
|
{
|
||||||
dsp::recorder::obj_t* recorder;
|
dsp::recorder::obj_t* recorder;
|
||||||
|
|
||||||
flow::external_device_t* deviceA;
|
flow::external_device_t* deviceA; // deviceA[ deviceN ] - cloned exteranl device array
|
||||||
unsigned deviceN;
|
unsigned deviceN;
|
||||||
flow::handle_t flowH;
|
flow::handle_t flowH;
|
||||||
|
|
||||||
@ -47,7 +51,7 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct flow_cross_str
|
typedef struct flow_cross_str
|
||||||
{
|
{
|
||||||
unsigned cur_idx;
|
unsigned cur_idx; // index of the network currently receiving parameter updates
|
||||||
double srate;
|
double srate;
|
||||||
|
|
||||||
unsigned netN;
|
unsigned netN;
|
||||||
@ -106,8 +110,21 @@ namespace cw
|
|||||||
memcpy(devA,srcDevA,devN * sizeof(flow::external_device_t));
|
memcpy(devA,srcDevA,devN * sizeof(flow::external_device_t));
|
||||||
|
|
||||||
for(unsigned i=0; i<devN; ++i)
|
for(unsigned i=0; i<devN; ++i)
|
||||||
if( devA[i].typeId == flow::kAudioDevTypeId )
|
{
|
||||||
|
switch( devA[i].typeId )
|
||||||
|
{
|
||||||
|
case flow::kAudioDevTypeId:
|
||||||
devA[i].u.a.abuf = _clone_abuf( srcDevA[i].u.a.abuf );
|
devA[i].u.a.abuf = _clone_abuf( srcDevA[i].u.a.abuf );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case flow::kMidiDevTypeId:
|
||||||
|
devA[i].u.m = srcDevA[i].u.m;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return devA;
|
return devA;
|
||||||
}
|
}
|
||||||
@ -130,7 +147,7 @@ namespace cw
|
|||||||
net->stateId = net_idx == 0 ? kActiveStateId : kInactiveStateId;
|
net->stateId = net_idx == 0 ? kActiveStateId : kInactiveStateId;
|
||||||
net->net_idx = net_idx;
|
net->net_idx = net_idx;
|
||||||
|
|
||||||
if((rc = flow::create( net->flowH, classCfg, networkCfg, net->deviceA, deviceN )) == kOkRC )
|
if((rc = flow::create( net->flowH, &classCfg, &networkCfg, nullptr, nullptr, net->deviceA, deviceN )) == kOkRC )
|
||||||
net->deviceN = deviceN;
|
net->deviceN = deviceN;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -203,9 +220,20 @@ namespace cw
|
|||||||
|
|
||||||
if( net->stateId == kFadeOutStateId && ef == 0.0 )
|
if( net->stateId == kFadeOutStateId && ef == 0.0 )
|
||||||
net->stateId = kInactiveStateId;
|
net->stateId = kInactiveStateId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy audio from the actual external audio device to a cloned audio device
|
||||||
|
void _update_midi_input( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
||||||
|
{
|
||||||
|
flow::midi_dev_cfg_t& src = p->deviceA[devIdx].u.m; // src MIDI device
|
||||||
|
flow::midi_dev_cfg_t& dst = net->deviceA[devIdx].u.m; // dst MIDI device clone
|
||||||
|
|
||||||
|
// redirect the MIDI msg list array to the clones
|
||||||
|
dst.msgArray = src.msgArray;
|
||||||
|
dst.msgCnt = src.msgCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy audio from the actual external audio device to a cloned audio device
|
||||||
void _update_audio_input( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
void _update_audio_input( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
||||||
{
|
{
|
||||||
flow::abuf_t* src = p->deviceA[devIdx].u.a.abuf;
|
flow::abuf_t* src = p->deviceA[devIdx].u.a.abuf;
|
||||||
@ -216,6 +244,7 @@ namespace cw
|
|||||||
//_fade_audio( src, dst, net );
|
//_fade_audio( src, dst, net );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _zero_audio_output( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
void _zero_audio_output( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
||||||
{
|
{
|
||||||
flow::abuf_t* dst = net->deviceA[devIdx].u.a.abuf;
|
flow::abuf_t* dst = net->deviceA[devIdx].u.a.abuf;
|
||||||
@ -378,12 +407,26 @@ cw::rc_t cw::flow_cross::exec_cycle( handle_t h )
|
|||||||
{
|
{
|
||||||
flow_network_t* net = p->netA + i;
|
flow_network_t* net = p->netA + i;
|
||||||
|
|
||||||
|
for(unsigned j=0; j<p->deviceN; ++j)
|
||||||
|
if( cwIsFlag(p->deviceA[j].flags, flow::kInFl ) )
|
||||||
|
{
|
||||||
|
switch( p->deviceA[j].typeId)
|
||||||
|
{
|
||||||
|
case flow::kAudioDevTypeId:
|
||||||
// We generally don't want to fade the input because the state
|
// We generally don't want to fade the input because the state
|
||||||
// of the network delay lines would then be invalid when the
|
// of the network delay lines would then be invalid when the
|
||||||
// network is eventually made active again
|
// network is eventually made active again
|
||||||
for(unsigned j=0; j<p->deviceN; ++j)
|
|
||||||
if( p->deviceA[j].typeId == flow::kAudioDevTypeId && cwIsFlag(p->deviceA[j].flags, flow::kInFl ) )
|
// copy audio from the actual audio device to the cloned audio devices
|
||||||
_update_audio_input( p, p->netA + i, j );
|
_update_audio_input( p, p->netA + i, j );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case flow::kMidiDevTypeId:
|
||||||
|
// update the cloned MIDI devices from the master device
|
||||||
|
_update_midi_input( p, p->netA + i, j );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// zero the audio device output buffers because we are about to sum into them
|
// zero the audio device output buffers because we are about to sum into them
|
||||||
for(unsigned j=0; j<p->deviceN; ++j)
|
for(unsigned j=0; j<p->deviceN; ++j)
|
||||||
|
61
cwFlowDecl.h
61
cwFlowDecl.h
@ -5,6 +5,67 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace flow
|
namespace flow
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kAudioDevTypeId,
|
||||||
|
kMidiDevTypeId,
|
||||||
|
kSerialDevTypeId,
|
||||||
|
kSocketDevTypeId
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kInFl = 0x01,
|
||||||
|
kOutFl = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct abuf_str;
|
||||||
|
|
||||||
|
typedef struct audio_dev_cfg_str
|
||||||
|
{
|
||||||
|
struct abuf_str* abuf; // Buffer to receive incoming or send outgoing audio for this device
|
||||||
|
// The audio_in/audio_out proc's locate and use these buffers.
|
||||||
|
} audio_dev_cfg_t;
|
||||||
|
|
||||||
|
struct external_device_str;
|
||||||
|
|
||||||
|
typedef rc_t (*send_midi_triple_func_t)( struct external_device_str* dev, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 );
|
||||||
|
|
||||||
|
typedef struct midi_dev_cfg_str
|
||||||
|
{
|
||||||
|
// msgArray[] contains the current msgs for all devices NOT just the device that this record is embedded in.
|
||||||
|
// We do this so that the order of messages as they arrived is maintained. Otherwise, to achieve this ordering,
|
||||||
|
// the messages for all devices would need to be collected and sorted by time.
|
||||||
|
const midi::ch_msg_t* msgArray;
|
||||||
|
unsigned msgCnt;
|
||||||
|
|
||||||
|
unsigned maxMsgCnt; // max possible value of msgCnt
|
||||||
|
send_midi_triple_func_t sendTripleFunc;
|
||||||
|
} midi_dev_cfg_t;
|
||||||
|
|
||||||
|
// Generate external device record
|
||||||
|
typedef struct external_device_str
|
||||||
|
{
|
||||||
|
void* reserved;
|
||||||
|
const char* devLabel; // IO framework device label
|
||||||
|
const char* portLabel; // IO framework MIDI port label (only used by MIDI devices)
|
||||||
|
unsigned typeId; // see ???DevTypeId above
|
||||||
|
unsigned flags; // see ???Fl above
|
||||||
|
|
||||||
|
unsigned ioDevIdx; // IO framework device index
|
||||||
|
unsigned ioPortIdx; // IO framework MIDI port index (only used by MIDI devices)
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
audio_dev_cfg_t a; // audio devices use this record
|
||||||
|
midi_dev_cfg_t m; // MIDI " " " "
|
||||||
|
} u;
|
||||||
|
|
||||||
|
} external_device_t;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kPriPresetProbFl = 0x01,
|
kPriPresetProbFl = 0x01,
|
||||||
kSecPresetProbFl = 0x02,
|
kSecPresetProbFl = 0x02,
|
||||||
|
3591
cwFlowNet.cpp
Normal file
3591
cwFlowNet.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
cwFlowNet.h
Normal file
87
cwFlowNet.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#ifndef cwFlowNet_h
|
||||||
|
#define cwFlowNet_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace flow
|
||||||
|
{
|
||||||
|
typedef enum {
|
||||||
|
kNetFirstPolyOrderId,
|
||||||
|
kProcFirstPolyOrderId
|
||||||
|
} network_order_id_t;
|
||||||
|
|
||||||
|
rc_t network_create( flow_t* p,
|
||||||
|
const object_t* networkCfg,
|
||||||
|
network_t& net, // Network object to be filled with new proc instances
|
||||||
|
variable_t* proxyVarL, //
|
||||||
|
unsigned polyCnt = 1, // Count of networks to create
|
||||||
|
network_order_id_t orderId = kNetFirstPolyOrderId // Set the network exec order.
|
||||||
|
);
|
||||||
|
|
||||||
|
rc_t network_destroy( network_t& net );
|
||||||
|
|
||||||
|
const object_t* find_network_preset( const network_t& net, const char* presetLabel );
|
||||||
|
|
||||||
|
rc_t exec_cycle( network_t& net );
|
||||||
|
|
||||||
|
|
||||||
|
rc_t get_variable( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, proc_t*& instPtrRef, variable_t*& varPtrRef );
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t set_variable_value( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, T value )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
proc_t* inst = nullptr;
|
||||||
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
|
// get the variable
|
||||||
|
if((rc = get_variable(net,inst_label,var_label,chIdx,inst,var)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// set the variable value
|
||||||
|
if((rc = var_set( inst, var->vid, chIdx, value )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"The variable set failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t get_variable_value( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, T& valueRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
proc_t* inst = nullptr;
|
||||||
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
|
// get the variable
|
||||||
|
if((rc = get_variable(net,inst_label,var_label,chIdx,inst,var)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// get the variable value
|
||||||
|
if((rc = var_get( inst, var->vid, chIdx, valueRef )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"The variable get failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'proc_label_sfx_id' is the proc label_sfx_id to be used to identify all proc's which will
|
||||||
|
// be updated by the preset application. This is used to identify the set of procs to be updated
|
||||||
|
// for 'poly' networks.
|
||||||
|
// If 'proc_label_sfx_id' is set to 'kInvalidId' then the preset will be applied to all proc's.
|
||||||
|
rc_t network_apply_preset( network_t& net, const char* presetLabel, unsigned proc_label_sfx_id=kInvalidId );
|
||||||
|
rc_t network_apply_dual_preset( network_t& net, const char* presetLabel_0, const char* presetLabel_1, double coeff, unsigned proc_label_sfx_id=kInvalidId );
|
||||||
|
rc_t network_apply_preset( network_t& net, const multi_preset_selector_t& mps, unsigned proc_label_sfx_id=kInvalidId );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
3328
cwFlowProc.cpp
3328
cwFlowProc.cpp
File diff suppressed because it is too large
Load Diff
19
cwFlowProc.h
19
cwFlowProc.h
@ -2,10 +2,14 @@ namespace cw
|
|||||||
{
|
{
|
||||||
namespace flow
|
namespace flow
|
||||||
{
|
{
|
||||||
|
namespace subnet { extern class_members_t members; }
|
||||||
|
namespace poly { extern class_members_t members; }
|
||||||
|
namespace midi_in { extern class_members_t members; }
|
||||||
|
namespace midi_out { extern class_members_t members; }
|
||||||
namespace audio_in { extern class_members_t members; }
|
namespace audio_in { extern class_members_t members; }
|
||||||
namespace audio_out { extern class_members_t members; }
|
namespace audio_out { extern class_members_t members; }
|
||||||
namespace audioFileIn { extern class_members_t members; }
|
namespace audio_file_in { extern class_members_t members; }
|
||||||
namespace audioFileOut { extern class_members_t members; }
|
namespace audio_file_out { extern class_members_t members; }
|
||||||
namespace audio_gain { extern class_members_t members; }
|
namespace audio_gain { extern class_members_t members; }
|
||||||
namespace audio_split { extern class_members_t members; }
|
namespace audio_split { extern class_members_t members; }
|
||||||
namespace audio_merge { extern class_members_t members; }
|
namespace audio_merge { extern class_members_t members; }
|
||||||
@ -22,5 +26,16 @@ namespace cw
|
|||||||
namespace balance { extern class_members_t members; }
|
namespace balance { extern class_members_t members; }
|
||||||
namespace audio_meter { extern class_members_t members; }
|
namespace audio_meter { extern class_members_t members; }
|
||||||
namespace audio_marker { extern class_members_t members; }
|
namespace audio_marker { extern class_members_t members; }
|
||||||
|
namespace xfade_ctl { extern class_members_t members; }
|
||||||
|
namespace poly_merge { extern class_members_t members; }
|
||||||
|
namespace sample_hold { extern class_members_t members; }
|
||||||
|
namespace number { extern class_members_t members; }
|
||||||
|
namespace timer { extern class_members_t members; }
|
||||||
|
namespace counter { extern class_members_t members; }
|
||||||
|
namespace list { extern class_members_t members; }
|
||||||
|
namespace add { extern class_members_t members; }
|
||||||
|
namespace preset { extern class_members_t members; }
|
||||||
|
namespace print { extern class_members_t members; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
81
cwFlowTest.cpp
Normal file
81
cwFlowTest.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwText.h"
|
||||||
|
#include "cwNumericConvert.h"
|
||||||
|
#include "cwObject.h"
|
||||||
|
|
||||||
|
#include "cwTime.h"
|
||||||
|
#include "cwMidiDecls.h"
|
||||||
|
#include "cwMidi.h"
|
||||||
|
#include "cwFlowDecl.h"
|
||||||
|
#include "cwFlow.h"
|
||||||
|
#include "cwFlowTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::flow::test( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* proc_cfg_fname = nullptr;
|
||||||
|
const char* subnet_cfg_fname = nullptr;
|
||||||
|
object_t* class_cfg = nullptr;
|
||||||
|
object_t* subnet_cfg = nullptr;
|
||||||
|
handle_t flowH;
|
||||||
|
|
||||||
|
if( args.module_args == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The flow test cases require module args.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = args.module_args->readv("proc_cfg_fname",0,proc_cfg_fname,
|
||||||
|
"subnet_cfg_fname",0,subnet_cfg_fname)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Flow module arg's parse failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the proc dict. file
|
||||||
|
if((rc = objectFromFile(proc_cfg_fname,class_cfg)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The flow proc dictionary could not be read from '%s'.",cwStringNullGuard(proc_cfg_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the subnet dict file
|
||||||
|
if((rc = objectFromFile(subnet_cfg_fname,subnet_cfg)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The flow subnet dictionary could not be read from '%s'.",cwStringNullGuard(subnet_cfg_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the flow object
|
||||||
|
if((rc = create( flowH, class_cfg, args.test_args, subnet_cfg, args.out_dir)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Flow object create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the network
|
||||||
|
if((rc = exec( flowH )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Execution failed.");
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
// destroy the flow object
|
||||||
|
if((rc = destroy(flowH)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Close the flow object.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( class_cfg != nullptr )
|
||||||
|
class_cfg->free();
|
||||||
|
|
||||||
|
if( subnet_cfg != nullptr )
|
||||||
|
subnet_cfg->free();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
9
cwFlowTest.h
Normal file
9
cwFlowTest.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace flow
|
||||||
|
{
|
||||||
|
|
||||||
|
rc_t test( const test::test_args_t& args );
|
||||||
|
}
|
||||||
|
}
|
1920
cwFlowTypes.cpp
1920
cwFlowTypes.cpp
File diff suppressed because it is too large
Load Diff
479
cwFlowTypes.h
479
cwFlowTypes.h
@ -3,20 +3,28 @@ namespace cw
|
|||||||
namespace flow
|
namespace flow
|
||||||
{
|
{
|
||||||
|
|
||||||
#define kRealTFl kFloatTFl
|
typedef dsp::coeff_t coeff_t;
|
||||||
typedef dsp::real_t real_t;
|
|
||||||
typedef dsp::sample_t sample_t;
|
typedef dsp::sample_t sample_t;
|
||||||
typedef dsp::fd_real_t fd_real_t;
|
typedef dsp::fd_sample_t fd_sample_t;
|
||||||
typedef dsp::srate_t srate_t;
|
typedef dsp::srate_t srate_t;
|
||||||
|
typedef dsp::ftime_t ftime_t;
|
||||||
typedef unsigned uint_t;
|
typedef unsigned uint_t;
|
||||||
typedef int int_t;
|
typedef int int_t;
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned vid_t;
|
typedef unsigned vid_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kBaseSfxId = 0,
|
||||||
|
kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz)
|
||||||
|
kAnyChIdx = kInvalidIdx,
|
||||||
|
kLocalValueN = 2,
|
||||||
|
kDefaultFramesPerCycle=64,
|
||||||
|
kDefaultSampleRate=48000
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct abuf_str
|
typedef struct abuf_str
|
||||||
{
|
{
|
||||||
struct value_str* base;
|
|
||||||
srate_t srate; // signal sample rate
|
srate_t srate; // signal sample rate
|
||||||
unsigned chN; // count of channels
|
unsigned chN; // count of channels
|
||||||
unsigned frameN; // count of sample frames per channel
|
unsigned frameN; // count of sample frames per channel
|
||||||
@ -24,28 +32,27 @@ namespace cw
|
|||||||
} abuf_t;
|
} abuf_t;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz)
|
|
||||||
kAnyChIdx = kInvalidIdx,
|
|
||||||
kLocalValueN = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct fbuf_str
|
typedef struct fbuf_str
|
||||||
{
|
{
|
||||||
struct value_str* base;
|
|
||||||
srate_t srate; // signal sample rate
|
srate_t srate; // signal sample rate
|
||||||
unsigned flags; // See kXXXFbufFl
|
unsigned flags; // See kXXXFbufFl
|
||||||
unsigned chN; // count of channels
|
unsigned chN; // count of channels
|
||||||
unsigned* maxBinN_V; // max value that binN_V[i] is allowed to take
|
unsigned* maxBinN_V; // max value that binN_V[i] is allowed to take
|
||||||
unsigned* binN_V; // binN_V[ chN ] count of sample frames per channel
|
unsigned* binN_V; // binN_V[ chN ] count of sample frames per channel
|
||||||
unsigned* hopSmpN_V; // hopSmpN_V[ chN ] hop sample count
|
unsigned* hopSmpN_V; // hopSmpN_V[ chN ] hop sample count
|
||||||
fd_real_t** magV; // magV[ chN ][ binN ]
|
fd_sample_t** magV; // magV[ chN ][ binN ]
|
||||||
fd_real_t** phsV; // phsV[ chN ][ binN ]
|
fd_sample_t** phsV; // phsV[ chN ][ binN ]
|
||||||
fd_real_t** hzV; // hzV[ chN ][ binN ]
|
fd_sample_t** hzV; // hzV[ chN ][ binN ]
|
||||||
bool* readyFlV; // readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate)
|
bool* readyFlV; // readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate)
|
||||||
fd_real_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer)
|
fd_sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer)
|
||||||
} fbuf_t;
|
} fbuf_t;
|
||||||
|
|
||||||
|
typedef struct mbuf_str
|
||||||
|
{
|
||||||
|
const midi::ch_msg_t* msgA;
|
||||||
|
unsigned msgN;
|
||||||
|
} mbuf_t;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kInvalidTFl = 0x00000000,
|
kInvalidTFl = 0x00000000,
|
||||||
@ -58,17 +65,23 @@ namespace cw
|
|||||||
kBoolMtxTFl = 0x00000020,
|
kBoolMtxTFl = 0x00000020,
|
||||||
kUIntMtxTFl = 0x00000040,
|
kUIntMtxTFl = 0x00000040,
|
||||||
kIntMtxTFl = 0x00000080,
|
kIntMtxTFl = 0x00000080,
|
||||||
kRealMtxTFl = 0x00000100,
|
kFloatMtxTFl = 0x00000100,
|
||||||
kFloatMtxTFl = 0x00000200,
|
kDoubleMtxTFl= 0x00000200,
|
||||||
kDoubleMtxTFl= 0x00000400,
|
|
||||||
|
|
||||||
kABufTFl = 0x00000800,
|
kABufTFl = 0x00000400,
|
||||||
kFBufTFl = 0x00001000,
|
kFBufTFl = 0x00000800,
|
||||||
|
kMBufTFl = 0x00001000,
|
||||||
kStringTFl = 0x00002000,
|
kStringTFl = 0x00002000,
|
||||||
kTimeTFl = 0x00004000,
|
kTimeTFl = 0x00004000,
|
||||||
|
kCfgTFl = 0x00008000,
|
||||||
|
|
||||||
kTypeMask = 0x00007fff,
|
kTypeMask = 0x0000ffff,
|
||||||
|
|
||||||
|
kRuntimeTFl = 0x80000000,
|
||||||
|
|
||||||
|
kNumericTFl = kBoolTFl | kUIntTFl | kIntTFl | kFloatTFl | kDoubleTFl,
|
||||||
|
kMtxTFl = kBoolMtxTFl | kUIntMtxTFl | kIntMtxTFl | kFloatMtxTFl | kDoubleMtxTFl,
|
||||||
|
kAllTFl = kTypeMask
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mtx_str
|
typedef struct mtx_str
|
||||||
@ -76,7 +89,6 @@ namespace cw
|
|||||||
union {
|
union {
|
||||||
struct mtx::mtx_str< unsigned >* u;
|
struct mtx::mtx_str< unsigned >* u;
|
||||||
struct mtx::mtx_str< int >* i;
|
struct mtx::mtx_str< int >* i;
|
||||||
struct mtx::mtx_str< real_t >* r;
|
|
||||||
struct mtx::mtx_str< float >* f;
|
struct mtx::mtx_str< float >* f;
|
||||||
struct mtx::mtx_str< double >* d;
|
struct mtx::mtx_str< double >* d;
|
||||||
} u;
|
} u;
|
||||||
@ -84,7 +96,8 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct value_str
|
typedef struct value_str
|
||||||
{
|
{
|
||||||
unsigned flags;
|
unsigned tflag;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
bool b;
|
bool b;
|
||||||
uint_t u;
|
uint_t u;
|
||||||
@ -93,12 +106,14 @@ namespace cw
|
|||||||
double d;
|
double d;
|
||||||
|
|
||||||
mtx_t* mtx;
|
mtx_t* mtx;
|
||||||
|
|
||||||
abuf_t* abuf;
|
abuf_t* abuf;
|
||||||
fbuf_t* fbuf;
|
fbuf_t* fbuf;
|
||||||
|
mbuf_t* mbuf;
|
||||||
|
|
||||||
char* s;
|
char* s;
|
||||||
char* fname;
|
|
||||||
|
const object_t* cfg;
|
||||||
|
void* p;
|
||||||
|
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
@ -107,19 +122,22 @@ namespace cw
|
|||||||
} value_t;
|
} value_t;
|
||||||
|
|
||||||
|
|
||||||
inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->flags,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); }
|
struct proc_str;
|
||||||
inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->flags,kBoolMtxTFl|kUIntMtxTFl|kIntMtxTFl|kFloatMtxTFl|kDoubleMtxTFl); }
|
|
||||||
|
|
||||||
struct instance_str;
|
|
||||||
struct variable_str;
|
struct variable_str;
|
||||||
|
|
||||||
typedef rc_t (*member_func_t)( struct instance_str* ctx );
|
typedef rc_t (*member_func_t)( struct proc_str* ctx );
|
||||||
typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var );
|
typedef rc_t (*member_value_func_t)( struct proc_str* ctx, struct variable_str* var );
|
||||||
|
|
||||||
|
// var_desc_t attribute flags
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kSrcVarFl = 0x01,
|
kInvalidVarDescFl = 0x00,
|
||||||
kSrcOptVarFl = 0x02
|
kSrcVarDescFl = 0x01,
|
||||||
|
kSrcOptVarDescFl = 0x02,
|
||||||
|
kNoSrcVarDescFl = 0x04,
|
||||||
|
kInitVarDescFl = 0x08,
|
||||||
|
kMultVarDescFl = 0x10,
|
||||||
|
kSubnetOutVarDescFl = 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct class_members_str
|
typedef struct class_members_str
|
||||||
@ -139,53 +157,83 @@ namespace cw
|
|||||||
unsigned type; // Value type id (e.g. kBoolTFl, kIntTFl, ...)
|
unsigned type; // Value type id (e.g. kBoolTFl, kIntTFl, ...)
|
||||||
unsigned flags; // Attributes for this var. (e.g. kSrcVarFl )
|
unsigned flags; // Attributes for this var. (e.g. kSrcVarFl )
|
||||||
const char* docText; // User help string for this var.
|
const char* docText; // User help string for this var.
|
||||||
|
|
||||||
|
char* proxyProcLabel;
|
||||||
|
char* proxyVarLabel;
|
||||||
|
|
||||||
struct var_desc_str* link; // class_desc->varDescL list link
|
struct var_desc_str* link; // class_desc->varDescL list link
|
||||||
} var_desc_t;
|
} var_desc_t;
|
||||||
|
|
||||||
typedef struct preset_str
|
typedef struct class_preset_str
|
||||||
{
|
{
|
||||||
const char* label;
|
const char* label;
|
||||||
const object_t* cfg;
|
const object_t* cfg;
|
||||||
struct preset_str* link;
|
struct class_preset_str* link;
|
||||||
} preset_t;
|
} class_preset_t;
|
||||||
|
|
||||||
typedef struct class_desc_str
|
typedef struct class_desc_str
|
||||||
{
|
{
|
||||||
const object_t* cfg; //
|
const object_t* cfg; // class cfg
|
||||||
const char* label; // class label;
|
const char* label; // class label;
|
||||||
var_desc_t* varDescL; // varDescA[varDescN] value description list
|
var_desc_t* varDescL; // varDescL variable description linked on var_desc_t.link
|
||||||
preset_t* presetL; // presetA[ presetN ]
|
class_preset_t* presetL; // presetA[ presetN ]
|
||||||
class_members_t* members; // member functions for this class
|
class_members_t* members; // member functions for this class
|
||||||
|
unsigned polyLimitN; // max. poly copies of this class per network_t or 0 if no limit
|
||||||
} class_desc_t;
|
} class_desc_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kInvalidVarFl = 0x00,
|
||||||
|
kLogVarFl = 0x01,
|
||||||
|
kProxiedVarFl = 0x02,
|
||||||
|
kProxiedOutVarFl = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
// Note: The concatenation of 'vid' and 'chIdx' should form a unique identifier among all variables
|
// Note: The concatenation of 'vid' and 'chIdx' should form a unique identifier among all variables
|
||||||
// on a given 'instance'.
|
// on a given 'instance'.
|
||||||
typedef struct variable_str
|
typedef struct variable_str
|
||||||
{
|
{
|
||||||
struct instance_str* inst; // pointer to this variables instance
|
struct proc_str* proc; // pointer to this variables instance
|
||||||
|
|
||||||
char* label; // this variables label
|
char* label; // this variables label
|
||||||
unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'inst'
|
unsigned label_sfx_id; // the label suffix id of this variable or kBaseSfxId if this has no suffix
|
||||||
var_desc_t* varDesc; // the variable description for this variable
|
|
||||||
|
unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'proc'
|
||||||
|
unsigned chIdx; // channel index
|
||||||
|
unsigned flags; // kLogVarFl
|
||||||
|
unsigned type; // This is the value type as established when the var is initialized - it never changes for the life of the var.
|
||||||
|
|
||||||
|
var_desc_t* classVarDesc; // pointer to this variables class var desc
|
||||||
|
var_desc_t* localVarDesc; // pointer to this variables local var desc - if it doesn't match classVarDesc.
|
||||||
|
var_desc_t* varDesc; // the effective variable description for this variable (set to classVarDesc or localVarDesc)
|
||||||
|
|
||||||
value_t local_value[ kLocalValueN ]; // the local value instance (actual value if this is not a 'src' variable)
|
value_t local_value[ kLocalValueN ]; // the local value instance (actual value if this is not a 'src' variable)
|
||||||
unsigned local_value_idx; // local_value[] is double buffered to allow the cur value of the buf[] to be held while the next value is validated (see _var_set_template())
|
unsigned local_value_idx; // local_value[] is double buffered to allow the cur value of the buf[] to be held while the next value is validated (see _var_set_template())
|
||||||
value_t* value; // pointer to the value associated with this variable
|
|
||||||
unsigned chIdx; // channel index
|
|
||||||
struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value)
|
struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value)
|
||||||
struct variable_str* var_link; // instance.varL link list
|
value_t* value; // pointer to the value associated with this variable
|
||||||
struct variable_str* connect_link; // list of outgoing connections
|
|
||||||
|
struct variable_str* var_link; // instance.varL list link
|
||||||
struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number)
|
struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number)
|
||||||
|
|
||||||
|
struct variable_str* dst_head; // Pointer to list of out-going connections (null on var's that do not have out-going connections)
|
||||||
|
struct variable_str* dst_tail; //
|
||||||
|
struct variable_str* dst_link; // Link used by dst_head list.
|
||||||
|
|
||||||
} variable_t;
|
} variable_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct instance_str
|
struct network_str;
|
||||||
|
|
||||||
|
typedef struct proc_str
|
||||||
{
|
{
|
||||||
struct flow_str* ctx; // global system context
|
struct flow_str* ctx; // global system context
|
||||||
|
struct network_str* net; // network which owns this proc
|
||||||
|
|
||||||
class_desc_t* class_desc; //
|
class_desc_t* class_desc; //
|
||||||
|
|
||||||
const char* label; // instance label
|
char* label; // instance label
|
||||||
const object_t* inst_cfg; // instance configuration
|
unsigned label_sfx_id; // label suffix id (set to kBaseSfxId (0) unless poly is non-null)
|
||||||
|
|
||||||
|
const object_t* proc_cfg; // instance configuration
|
||||||
|
|
||||||
const char* arg_label; // optional args label
|
const char* arg_label; // optional args label
|
||||||
const object_t* arg_cfg; // optional args configuration
|
const object_t* arg_cfg; // optional args configuration
|
||||||
@ -199,32 +247,115 @@ namespace cw
|
|||||||
unsigned varMapN; // varMapN = varMapIdN * varMapChN
|
unsigned varMapN; // varMapN = varMapIdN * varMapChN
|
||||||
variable_t** varMapA; // varMapA[ varMapN ] = allows fast lookup from ('vid','chIdx) to variable
|
variable_t** varMapA; // varMapA[ varMapN ] = allows fast lookup from ('vid','chIdx) to variable
|
||||||
|
|
||||||
struct instance_str* link;
|
struct network_str* internal_net;
|
||||||
} instance_t;
|
|
||||||
|
|
||||||
|
} proc_t;
|
||||||
|
|
||||||
|
|
||||||
|
// preset_value_t holds a preset value and the proc/var to which it will be applied.
|
||||||
|
typedef struct preset_value_str
|
||||||
|
{
|
||||||
|
proc_t* proc; // proc target for this preset value
|
||||||
|
variable_t* var; // var target for this preset value
|
||||||
|
value_t value; // Preset value.
|
||||||
|
unsigned pairTblIdx; // Index into the preset pair table for this preset value
|
||||||
|
struct preset_value_str* link;
|
||||||
|
} preset_value_t;
|
||||||
|
|
||||||
|
typedef struct preset_value_list_str
|
||||||
|
{
|
||||||
|
preset_value_t* value_head; // List of preset_value_t for this preset.
|
||||||
|
preset_value_t* value_tail; // Last preset value in the list.
|
||||||
|
} preset_value_list_t;
|
||||||
|
|
||||||
|
struct network_preset_str;
|
||||||
|
|
||||||
|
typedef struct dual_preset_str
|
||||||
|
{
|
||||||
|
const struct network_preset_str* pri;
|
||||||
|
const struct network_preset_str* sec;
|
||||||
|
double coeff;
|
||||||
|
} dual_preset_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kPresetVListTId,
|
||||||
|
kPresetDualTId
|
||||||
|
} preset_type_id_t;
|
||||||
|
|
||||||
|
typedef struct network_preset_str
|
||||||
|
{
|
||||||
|
const char* label; // Preset label
|
||||||
|
preset_type_id_t tid;
|
||||||
|
|
||||||
|
union {
|
||||||
|
preset_value_list_t vlist;
|
||||||
|
dual_preset_t dual;
|
||||||
|
} u;
|
||||||
|
} network_preset_t;
|
||||||
|
|
||||||
|
// Preset-pair record used to apply dual presets.
|
||||||
|
typedef struct network_preset_pair_str
|
||||||
|
{
|
||||||
|
const proc_t* proc; //
|
||||||
|
const variable_t* var; //
|
||||||
|
unsigned chIdx; //
|
||||||
|
unsigned chN; //
|
||||||
|
const value_t* value; //
|
||||||
|
} network_preset_pair_t;
|
||||||
|
|
||||||
|
typedef struct network_str
|
||||||
|
{
|
||||||
|
const object_t* procsCfg; // network proc list
|
||||||
|
const object_t* presetsCfg; // presets designed for this network
|
||||||
|
unsigned poly_cnt; // count of duplicated networks in the list
|
||||||
|
|
||||||
|
struct proc_str** proc_array;
|
||||||
|
|
||||||
|
unsigned proc_arrayAllocN;
|
||||||
|
unsigned proc_arrayN;
|
||||||
|
|
||||||
|
network_preset_t* presetA;
|
||||||
|
unsigned presetN;
|
||||||
|
|
||||||
|
// Preset pair table used by network_apply_dual_preset()
|
||||||
|
network_preset_pair_t* preset_pairA;
|
||||||
|
unsigned preset_pairN;
|
||||||
|
|
||||||
|
} network_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct flow_str
|
typedef struct flow_str
|
||||||
{
|
{
|
||||||
const object_t* networkCfg; // complete cfg used to create this network
|
const object_t* flowCfg; // complete cfg used to create this flow
|
||||||
|
|
||||||
const object_t* presetCfg; // presets designed for this network
|
|
||||||
|
|
||||||
unsigned framesPerCycle; // sample frames per cycle (64)
|
unsigned framesPerCycle; // sample frames per cycle (64)
|
||||||
|
srate_t sample_rate; // default sample rate (48000.0)
|
||||||
|
unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit.
|
||||||
|
const char* init_net_preset_label;// network initialization preset label or nullptr if there is no net. init. preset
|
||||||
|
|
||||||
|
bool isInRuntimeFl; // Set when compile-time is complete
|
||||||
|
|
||||||
|
|
||||||
|
unsigned cycleIndex; // Incremented with each processing cycle
|
||||||
|
|
||||||
|
|
||||||
bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application
|
bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application
|
||||||
bool multiSecPresetProbFl; //
|
bool multiSecPresetProbFl; //
|
||||||
bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application
|
bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application
|
||||||
unsigned cycleIndex; // Incremented with each processing cycle
|
|
||||||
unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit.
|
|
||||||
|
|
||||||
class_desc_t* classDescA; //
|
class_desc_t* classDescA; //
|
||||||
unsigned classDescN; //
|
unsigned classDescN; //
|
||||||
|
|
||||||
|
class_desc_t* subnetDescA; //
|
||||||
|
unsigned subnetDescN; //
|
||||||
|
|
||||||
external_device_t* deviceA; // deviceA[ deviceN ] external device description array
|
external_device_t* deviceA; // deviceA[ deviceN ] external device description array
|
||||||
unsigned deviceN; //
|
unsigned deviceN; //
|
||||||
|
|
||||||
struct instance_str* network_head; // first instance
|
const char* proj_dir; // default input/output directory
|
||||||
struct instance_str* network_tail; // last insance
|
|
||||||
|
network_t net;
|
||||||
|
|
||||||
} flow_t;
|
} flow_t;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -232,32 +363,58 @@ namespace cw
|
|||||||
// Value Only
|
// Value Only
|
||||||
//
|
//
|
||||||
|
|
||||||
|
inline void set_null( value_t& v, unsigned tflag ) { v.tflag=tflag; v.u.p=nullptr; }
|
||||||
|
inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->tflag,kNumericTFl); }
|
||||||
|
inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->tflag,kMtxTFl); }
|
||||||
|
|
||||||
|
// if all of the src flags are set in the dst flags then the two types are convertable.
|
||||||
|
inline bool can_convert( unsigned src_tflag, unsigned dst_tflag ) { return (src_tflag&dst_tflag)==src_tflag; }
|
||||||
|
|
||||||
|
|
||||||
abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN );
|
abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN );
|
||||||
void abuf_destroy( abuf_t*& buf );
|
void abuf_destroy( abuf_t*& buf );
|
||||||
abuf_t* abuf_duplicate( const abuf_t* src );
|
abuf_t* abuf_duplicate( const abuf_t* src );
|
||||||
rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN );
|
rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN );
|
||||||
const sample_t* abuf_get_channel( abuf_t* buf, unsigned chIdx );
|
const sample_t* abuf_get_channel( abuf_t* buf, unsigned chIdx );
|
||||||
|
|
||||||
fbuf_t* fbuf_create( srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr );
|
fbuf_t* fbuf_create( srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr );
|
||||||
fbuf_t* fbuf_create( srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr );
|
fbuf_t* fbuf_create( srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr );
|
||||||
void fbuf_destroy( fbuf_t*& buf );
|
void fbuf_destroy( fbuf_t*& buf );
|
||||||
fbuf_t* fbuf_duplicate( const fbuf_t* src );
|
fbuf_t* fbuf_duplicate( const fbuf_t* src );
|
||||||
|
|
||||||
inline bool value_is_abuf( const value_t* v ) { return v->flags & kABufTFl; }
|
mbuf_t* mbuf_create( const midi::ch_msg_t* msgA=nullptr, unsigned msgN=0 );
|
||||||
inline bool value_is_fbuf( const value_t* v ) { return v->flags & kFBufTFl; }
|
void mbuf_destroy( mbuf_t*& buf );
|
||||||
|
mbuf_t* mbuf_duplicate( const mbuf_t* src );
|
||||||
|
|
||||||
|
inline bool value_is_abuf( const value_t* v ) { return v->tflag & kABufTFl; }
|
||||||
|
inline bool value_is_fbuf( const value_t* v ) { return v->tflag & kFBufTFl; }
|
||||||
|
|
||||||
unsigned value_type_label_to_flag( const char* type_desc );
|
unsigned value_type_label_to_flag( const char* type_desc );
|
||||||
|
const char* value_type_flag_to_label( unsigned flag );
|
||||||
|
|
||||||
|
void value_print( const value_t* value, bool info_fl=false);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Class and Variable Description
|
// Class and Variable Description
|
||||||
//
|
//
|
||||||
|
|
||||||
var_desc_t* var_desc_find( class_desc_t* cd, const char* var_label );
|
var_desc_t* var_desc_create( const char* label, const object_t* value_cfg );
|
||||||
rc_t var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef );
|
void var_desc_destroy( var_desc_t* var_desc );
|
||||||
|
|
||||||
|
unsigned var_desc_attr_label_to_flag( const char* attr_label );
|
||||||
|
const char* var_desc_flag_to_attribute( unsigned flag );
|
||||||
|
const idLabelPair_t* var_desc_flag_array( unsigned& array_cnt_ref );
|
||||||
|
|
||||||
|
void class_desc_destroy( class_desc_t* class_desc);
|
||||||
class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label );
|
class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label );
|
||||||
|
|
||||||
|
var_desc_t* var_desc_find( class_desc_t* cd, const char* var_label );
|
||||||
|
const var_desc_t* var_desc_find( const class_desc_t* cd, const char* var_label );
|
||||||
|
rc_t var_desc_find( class_desc_t* cd, const char* var_label, var_desc_t*& vdRef );
|
||||||
|
|
||||||
|
const class_preset_t* class_preset_find( const class_desc_t* cd, const char* preset_label );
|
||||||
|
|
||||||
void class_dict_print( flow_t* p );
|
void class_dict_print( flow_t* p );
|
||||||
|
|
||||||
|
|
||||||
@ -265,19 +422,37 @@ namespace cw
|
|||||||
//
|
//
|
||||||
// Network
|
// Network
|
||||||
//
|
//
|
||||||
void network_print( flow_t* p );
|
void network_print(const network_t& net );
|
||||||
|
|
||||||
|
const network_preset_t* network_preset_from_label( const network_t& net, const char* preset_label );
|
||||||
|
|
||||||
|
unsigned proc_mult_count( const network_t& net, const char* proc_label );
|
||||||
|
|
||||||
|
rc_t proc_mult_sfx_id_array( const network_t& net, const char* proc_label, unsigned* idA, unsigned idAllocN, unsigned& idN_ref );
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Instance
|
// Proc
|
||||||
//
|
//
|
||||||
|
|
||||||
instance_t* instance_find( flow_t* p, const char* inst_label );
|
void proc_destroy( proc_t* proc );
|
||||||
rc_t instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef );
|
rc_t proc_validate( proc_t* proc );
|
||||||
external_device_t* external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl );
|
|
||||||
|
|
||||||
void instance_print( instance_t* inst );
|
proc_t* proc_find( network_t& net, const char* proc_label, unsigned sfx_id );
|
||||||
|
rc_t proc_find( network_t& net, const char* proc_label, unsigned sfx_id, proc_t*& procPtrRef );
|
||||||
|
|
||||||
|
external_device_t* external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl, const char* midiPortLabel=nullptr );
|
||||||
|
|
||||||
|
void proc_print( proc_t* proc );
|
||||||
|
|
||||||
|
// Count of all var instances on this proc. This is a count of the length of proc->varL.
|
||||||
|
unsigned proc_var_count( proc_t* proc );
|
||||||
|
|
||||||
|
// If fname has a '$' prefix then the system project directory is prepended to it.
|
||||||
|
// If fname has a '~' then the users home directory is prepended to it.
|
||||||
|
// The returned string must be release with a call to mem::free().
|
||||||
|
char* proc_expand_filename( const proc_t* proc, const char* fname );
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -286,41 +461,68 @@ namespace cw
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Create a variable but do not assign it a value. Return a pointer to the new variable.
|
// Create a variable but do not assign it a value. Return a pointer to the new variable.
|
||||||
// Note: `value_cfg` is optional. Set it to NULL to ignore
|
// Notes:
|
||||||
rc_t var_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
|
// 1) `value_cfg` is optional. Set it to NULL to ignore
|
||||||
|
// 2) If `altTypeFl` is not set to kInvalidTFl then the var is assigned this type.
|
||||||
|
rc_t var_create( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, const object_t* value_cfg, unsigned altTypeFlag, variable_t*& varRef );
|
||||||
|
void var_destroy( variable_t* var );
|
||||||
|
|
||||||
// Channelizing creates a new var record with an explicit channel index to replace the
|
// Channelizing creates a new var record with an explicit channel index to replace the
|
||||||
// automatically generated variable whose channel index is set to 'all'.
|
// automatically generated variable whose channel index is set to 'all'.
|
||||||
rc_t var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef );
|
rc_t var_channelize( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef );
|
||||||
|
|
||||||
|
// Wrapper around call to var->proc->members->value()
|
||||||
|
rc_t var_call_custom_value_func( variable_t* var );
|
||||||
|
|
||||||
|
// Sets and get the var->flags field
|
||||||
|
unsigned var_flags( proc_t* proc, unsigned chIdx, const char* var_label, unsigned sfx_id, unsigned& flags_ref );
|
||||||
|
rc_t var_set_flags( proc_t* proc, unsigned chIdx, const char* var_label, unsigned sfx_id, unsigned flags );
|
||||||
|
rc_t var_clr_flags( proc_t* proc, unsigned chIdx, const char* var_label, unsigned sfx_id, unsigned flags );
|
||||||
|
|
||||||
// `value_cfg` is optional. Set it to NULL to ignore
|
// `value_cfg` is optional. Set it to NULL to ignore
|
||||||
rc_t var_register( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
|
rc_t var_register( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
|
||||||
|
|
||||||
// Returns true if this var is connected to an external proc variable
|
// Returns true if this var is connected to a source proc variable
|
||||||
bool is_connected_to_external_proc( const variable_t* var );
|
bool is_connected_to_source( const variable_t* var );
|
||||||
|
|
||||||
|
// Return true if this var is acting as a source for another var.
|
||||||
|
bool is_a_source_var( const variable_t* var );
|
||||||
|
|
||||||
|
// Connect in_var to src_var.
|
||||||
|
void var_connect( variable_t* src_var, variable_t* in_var );
|
||||||
|
|
||||||
|
// Disconnect an in_var from it's source
|
||||||
|
void var_disconnect( variable_t* in_var );
|
||||||
|
|
||||||
|
|
||||||
|
// Get the count of 'mult' vars associated with this var label.
|
||||||
|
unsigned var_mult_count( proc_t* proc, const char* var_label );
|
||||||
|
|
||||||
|
// Get all the label-sfx-id's associated with a give var label
|
||||||
|
rc_t var_mult_sfx_id_array( proc_t* proc, const char* var_label, unsigned* idA, unsigned idAllocN, unsigned& idN_ref );
|
||||||
|
|
||||||
//-----------------
|
//-----------------
|
||||||
//
|
//
|
||||||
// var_register
|
// var_register
|
||||||
//
|
//
|
||||||
|
|
||||||
inline rc_t _var_reg(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
|
inline rc_t _var_reg(cw::flow::proc_t*, unsigned int ) { return kOkRC; }
|
||||||
|
|
||||||
template< typename T0, typename T1, typename... ARGS >
|
template< typename T0, typename T1, typename... ARGS >
|
||||||
rc_t _var_reg( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, ARGS&&... args )
|
rc_t _var_reg( proc_t* proc, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, ARGS&&... args )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
variable_t* dummy = nullptr;
|
variable_t* dummy = nullptr;
|
||||||
if((rc = var_register( inst, var_label, vid, chIdx, nullptr, dummy )) == kOkRC )
|
if((rc = var_register( proc, var_label, sfx_id, vid, chIdx, nullptr, dummy )) == kOkRC )
|
||||||
if((rc = _var_reg( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
if((rc = _var_reg( proc, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call var_register() on a list of variables.
|
// Call var_register() on a list of variables.
|
||||||
template< typename... ARGS >
|
template< typename... ARGS >
|
||||||
rc_t var_register( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
rc_t var_register( proc_t* proc, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args )
|
||||||
{ return _var_reg( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
|
{ return _var_reg( proc, chIdx, vid, var_label, sfx_id, std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -329,28 +531,28 @@ namespace cw
|
|||||||
// var_register_and_get
|
// var_register_and_get
|
||||||
//
|
//
|
||||||
|
|
||||||
inline rc_t _var_register_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
|
inline rc_t _var_register_and_get(cw::flow::proc_t*, unsigned int ) { return kOkRC; }
|
||||||
|
|
||||||
template< typename T>
|
template< typename T>
|
||||||
rc_t var_register_and_get( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, T& valRef )
|
rc_t var_register_and_get( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, T& valRef )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
variable_t* var;
|
variable_t* var;
|
||||||
if((rc = var_register(inst,var_label,vid,chIdx,nullptr,var)) == kOkRC )
|
if((rc = var_register(proc,var_label,sfx_id,vid,chIdx,nullptr,var)) == kOkRC )
|
||||||
rc = var_get(var,valRef);
|
rc = var_get(var,valRef);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline rc_t _var_reg_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
|
inline rc_t _var_reg_and_get(cw::flow::proc_t*, unsigned int ) { return kOkRC; }
|
||||||
|
|
||||||
template< typename T0, typename T1, typename T2, typename... ARGS >
|
template< typename T0, typename T1, typename T2, typename... ARGS >
|
||||||
rc_t _var_reg_and_get( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2& valRef, ARGS&&... args )
|
rc_t _var_reg_and_get( proc_t* proc, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, T2& valRef, ARGS&&... args )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
|
|
||||||
if((rc = var_register_and_get( inst, var_label, vid, chIdx, valRef )) == kOkRC )
|
if((rc = var_register_and_get( proc, var_label, sfx_id, vid, chIdx, valRef )) == kOkRC )
|
||||||
if((rc = _var_reg_and_get( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
if((rc = _var_reg_and_get( proc, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -358,8 +560,8 @@ namespace cw
|
|||||||
|
|
||||||
// Call var_register_and_get() on a list of variables.
|
// Call var_register_and_get() on a list of variables.
|
||||||
template< typename... ARGS >
|
template< typename... ARGS >
|
||||||
rc_t var_register_and_get( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
rc_t var_register_and_get( proc_t* proc, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args )
|
||||||
{ return _var_reg_and_get( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
|
{ return _var_reg_and_get( proc, chIdx, vid, var_label, sfx_id, std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -371,25 +573,27 @@ namespace cw
|
|||||||
// var_register_and_set(). If the variable has not yet been created then it is created and assigned a value.
|
// var_register_and_set(). If the variable has not yet been created then it is created and assigned a value.
|
||||||
// If the variable has already been created then 'vid' and the value are updated.
|
// If the variable has already been created then 'vid' and the value are updated.
|
||||||
// (Note that abuf and fbuf values are not changed by this function only the 'vid' is updated.)
|
// (Note that abuf and fbuf values are not changed by this function only the 'vid' is updated.)
|
||||||
rc_t var_register_and_set( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef );
|
rc_t var_register_and_set( proc_t* proc, const char* label, unsigned sfx_id, unsigned vid, unsigned chIdx, variable_t*& varRef );
|
||||||
|
|
||||||
rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN );
|
rc_t var_register_and_set( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN );
|
||||||
rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr );
|
rc_t var_register_and_set( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, midi::ch_msg_t* midiA, unsigned midiN );
|
||||||
rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr );
|
rc_t var_register_and_set( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr );
|
||||||
|
rc_t var_register_and_set( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr );
|
||||||
|
|
||||||
inline rc_t _var_register_and_set(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
|
inline rc_t _var_register_and_set(cw::flow::proc_t*, unsigned int ) { return kOkRC; }
|
||||||
|
|
||||||
template< typename T0, typename T1, typename T2, typename... ARGS >
|
template< typename T0, typename T1, typename T2, typename... ARGS >
|
||||||
rc_t _var_register_and_set( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2 val, ARGS&&... args )
|
rc_t _var_register_and_set( proc_t* proc, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, T2 val, ARGS&&... args )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
|
|
||||||
variable_t* var = nullptr;
|
variable_t* var = nullptr;
|
||||||
if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) == kOkRC )
|
if((rc = var_register_and_set( proc, var_label, sfx_id, vid, chIdx, var)) == kOkRC )
|
||||||
{
|
{
|
||||||
var_set( inst, vid, chIdx, val );
|
if((rc = var_set( proc, vid, chIdx, val )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
if((rc = _var_register_and_set( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
if((rc = _var_register_and_set( proc, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,24 +602,33 @@ namespace cw
|
|||||||
|
|
||||||
// Call var_register_and_set() on a list of variables.
|
// Call var_register_and_set() on a list of variables.
|
||||||
template< typename... ARGS >
|
template< typename... ARGS >
|
||||||
rc_t var_register_and_set( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
rc_t var_register_and_set( proc_t* proc, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args )
|
||||||
{ return _var_register_and_set( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
|
{ return _var_register_and_set( proc, chIdx, vid, var_label, sfx_id, std::forward<ARGS>(args)...); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _var_destroy( variable_t* var );
|
void _var_destroy( variable_t* var );
|
||||||
|
|
||||||
bool var_exists( instance_t* inst, const char* label, unsigned chIdx );
|
bool var_exists( proc_t* proc, const char* label, unsigned sfx_id, unsigned chIdx );
|
||||||
bool var_has_value( instance_t* inst, const char* label, unsigned chIdx );
|
bool var_has_value( proc_t* proc, const char* label, unsigned sfx_id, unsigned chIdx );
|
||||||
|
bool var_is_a_source( proc_t* proc, const char* label, unsigned sfx_id, unsigned chIdx );
|
||||||
|
bool var_is_a_source( proc_t* proc, unsigned vid, unsigned chIdx );
|
||||||
|
|
||||||
|
rc_t var_find( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned chIdx, const variable_t*& varRef );
|
||||||
|
rc_t var_find( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned chIdx, variable_t*& varRef );
|
||||||
|
rc_t var_find( proc_t* proc, unsigned vid, unsigned chIdx, variable_t*& varRef );
|
||||||
|
|
||||||
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef );
|
|
||||||
rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef );
|
|
||||||
rc_t var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef );
|
|
||||||
|
|
||||||
// Count of numbered channels - does not count the kAnyChIdx variable instance.
|
// Count of numbered channels - does not count the kAnyChIdx variable instance.
|
||||||
rc_t var_channel_count( instance_t* inst, const char* label, unsigned& chCntRef );
|
rc_t var_channel_count( proc_t* proc, const char* label, unsigned sfx_idx, unsigned& chCntRef );
|
||||||
rc_t var_channel_count( const variable_t* var, unsigned& chCntRef );
|
rc_t var_channel_count( const variable_t* var, unsigned& chCntRef );
|
||||||
|
|
||||||
|
rc_t cfg_to_value( const object_t* cfg, value_t& value_ref );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// var_get() coerces the value of the variable to the type of the returned value.
|
||||||
|
//
|
||||||
|
|
||||||
rc_t var_get( const variable_t* var, bool& valRef );
|
rc_t var_get( const variable_t* var, bool& valRef );
|
||||||
rc_t var_get( const variable_t* var, uint_t& valRef );
|
rc_t var_get( const variable_t* var, uint_t& valRef );
|
||||||
@ -427,37 +640,59 @@ namespace cw
|
|||||||
rc_t var_get( variable_t* var, abuf_t*& valRef );
|
rc_t var_get( variable_t* var, abuf_t*& valRef );
|
||||||
rc_t var_get( const variable_t* var, const fbuf_t*& valRef );
|
rc_t var_get( const variable_t* var, const fbuf_t*& valRef );
|
||||||
rc_t var_get( variable_t* var, fbuf_t*& valRef );
|
rc_t var_get( variable_t* var, fbuf_t*& valRef );
|
||||||
|
rc_t var_get( const variable_t* var, const mbuf_t*& valRef );
|
||||||
|
rc_t var_get( variable_t* var, mbuf_t*& valRef );
|
||||||
|
rc_t var_get( const variable_t* var, const object_t*& valRef );
|
||||||
|
|
||||||
template< typename T>
|
template< typename T>
|
||||||
rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, T& valRef)
|
rc_t var_get( proc_t* proc, unsigned vid, unsigned chIdx, T& valRef)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
variable_t* var = nullptr;
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
if((rc = var_find(inst, vid, chIdx, var )) == kOkRC )
|
if((rc = var_find(proc, vid, chIdx, var )) == kOkRC )
|
||||||
rc = var_get(var,valRef);
|
rc = var_get(var,valRef);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
T val_get( instance_t* inst, unsigned vid, unsigned chIdx )
|
T val_get( proc_t* proc, unsigned vid, unsigned chIdx )
|
||||||
{
|
{
|
||||||
T value;
|
T value;
|
||||||
var_get(inst,vid,chIdx,value);
|
var_get(proc,vid,chIdx,value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool val );
|
//
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint_t val );
|
// var_set() coerces the incoming value to the type of the variable (var->type)
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_t val );
|
//
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, float val );
|
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, double val );
|
rc_t var_set_from_cfg( variable_t* var, const object_t* cfg_value );
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, const char* val );
|
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, abuf_t* val );
|
rc_t var_set( variable_t* var, const value_t* val );
|
||||||
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t* val );
|
rc_t var_set( variable_t* var, bool val );
|
||||||
|
rc_t var_set( variable_t* var, uint_t val );
|
||||||
|
rc_t var_set( variable_t* var, int_t val );
|
||||||
|
rc_t var_set( variable_t* var, float val );
|
||||||
|
rc_t var_set( variable_t* var, double val );
|
||||||
|
rc_t var_set( variable_t* var, const char* val );
|
||||||
|
rc_t var_set( variable_t* var, abuf_t* val );
|
||||||
|
rc_t var_set( variable_t* var, fbuf_t* val );
|
||||||
|
rc_t var_set( variable_t* var, mbuf_t* val );
|
||||||
|
rc_t var_set( variable_t* var, const object_t* val );
|
||||||
|
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, const value_t* val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, bool val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, uint_t val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, int_t val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, float val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, double val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, const char* val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, abuf_t* val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, fbuf_t* val );
|
||||||
|
rc_t var_set( proc_t* proc, unsigned vid, unsigned chIdx, const object_t* val );
|
||||||
|
|
||||||
const preset_t* class_preset_find( class_desc_t* cd, const char* preset_label );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
52
cwIo.cpp
52
cwIo.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
@ -611,7 +612,7 @@ namespace cw
|
|||||||
//
|
//
|
||||||
// MIDI
|
// MIDI
|
||||||
//
|
//
|
||||||
void _midiCallback( const midi::packet_t* pktArray, unsigned pktCnt )
|
void _midiCallback( void* cbArg, const midi::packet_t* pktArray, unsigned pktCnt )
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for(i=0; i<pktCnt; ++i)
|
for(i=0; i<pktCnt; ++i)
|
||||||
@ -619,7 +620,7 @@ namespace cw
|
|||||||
msg_t m;
|
msg_t m;
|
||||||
midi_msg_t mm;
|
midi_msg_t mm;
|
||||||
const midi::packet_t* pkt = pktArray + i;
|
const midi::packet_t* pkt = pktArray + i;
|
||||||
io_t* p = reinterpret_cast<io_t*>(pkt->cbArg);
|
io_t* p = reinterpret_cast<io_t*>(cbArg);
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
|
||||||
@ -2115,9 +2116,11 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
if( rc != kOkRC && p->audioH.isValid() )
|
||||||
audio::device::report( p->audioH );
|
audio::device::report( p->audioH );
|
||||||
|
|
||||||
errLabel:
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2439,7 +2442,8 @@ cw::rc_t cw::io::stop( handle_t h )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::io::exec( handle_t h, void* execCbArg )
|
|
||||||
|
cw::rc_t cw::io::exec( handle_t h, unsigned timeOutMs, void* execCbArg )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
@ -2447,8 +2451,9 @@ cw::rc_t cw::io::exec( handle_t h, void* execCbArg )
|
|||||||
if( p->wsUiH.isValid() )
|
if( p->wsUiH.isValid() )
|
||||||
{
|
{
|
||||||
ui::flushCache( ui::ws::uiHandle( p->wsUiH ));
|
ui::flushCache( ui::ws::uiHandle( p->wsUiH ));
|
||||||
|
|
||||||
// Note this call blocks on the websocket handle: See cwUi.h:ws:exec()
|
// Note this call blocks on the websocket handle: See cwUi.h:ws:exec()
|
||||||
rc = ui::ws::exec( p->wsUiH );
|
rc = ui::ws::exec( p->wsUiH, timeOutMs );
|
||||||
}
|
}
|
||||||
|
|
||||||
time::get(p->t0);
|
time::get(p->t0);
|
||||||
@ -2490,14 +2495,23 @@ void cw::io::report( handle_t h )
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned i=0; i<audioDeviceCount(h); ++i)
|
for(unsigned i=0; i<audioDeviceCount(h); ++i)
|
||||||
printf("audio: %s\n", audioDeviceName(h,i));
|
printf("audio: %s\n", cwStringNullGuard(audioDeviceName(h,i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cw::io::hardwareReport( handle_t h )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
audio::device::report( p->audioH );
|
||||||
|
midi::device::report(p->midiH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void cw::io::realTimeReport( handle_t h )
|
void cw::io::realTimeReport( handle_t h )
|
||||||
{
|
{
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
audio::device::realTimeReport(p->audioH);
|
audio::device::realTimeReport(p->audioH);
|
||||||
|
uiRealTimeReport(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2747,6 +2761,24 @@ cw::rc_t cw::io::midiDeviceSend( handle_t h, unsigned devIdx, unsigned portIdx,
|
|||||||
return midi::device::send( p->midiH, devIdx, portIdx, status, d0, d1 );
|
return midi::device::send( p->midiH, devIdx, portIdx, status, d0, d1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned cw::io::midiDeviceMaxBufferMsgCount( handle_t h )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
return midi::device::maxBufferMsgCount(p->midiH );
|
||||||
|
}
|
||||||
|
|
||||||
|
const cw::midi::ch_msg_t* cw::io::midiDeviceBuffer( handle_t h, unsigned& msgCntRef )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
return midi::device::getBuffer(p->midiH, msgCntRef );
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::midiDeviceClearBuffer( handle_t h, unsigned msgCnt )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
return midi::device::clearBuffer(p->midiH, msgCnt );
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::io::midiOpenMidiFile( handle_t h, unsigned devIdx, unsigned portIdx, const char* fname )
|
cw::rc_t cw::io::midiOpenMidiFile( handle_t h, unsigned devIdx, unsigned portIdx, const char* fname )
|
||||||
{
|
{
|
||||||
return midi::device::openMidiFile( _handleToPtr(h)->midiH, devIdx, portIdx, fname );
|
return midi::device::openMidiFile( _handleToPtr(h)->midiH, devIdx, portIdx, fname );
|
||||||
@ -3967,8 +3999,8 @@ void cw::io::uiReport( handle_t h )
|
|||||||
|
|
||||||
void cw::io::uiRealTimeReport( handle_t h )
|
void cw::io::uiRealTimeReport( handle_t h )
|
||||||
{
|
{
|
||||||
ui::handle_t uiH;
|
ui::ws::handle_t uiH;
|
||||||
if(_handleToUiHandle(h,uiH) == kOkRC )
|
if(_handleToWsUiHandle(h,uiH) == kOkRC )
|
||||||
ui::realTimeReport(uiH);
|
ui::ws::realTimeReport(uiH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
cwIo.h
12
cwIo.h
@ -165,14 +165,17 @@ namespace cw
|
|||||||
rc_t pause( handle_t h );
|
rc_t pause( handle_t h );
|
||||||
rc_t stop( handle_t h );
|
rc_t stop( handle_t h );
|
||||||
|
|
||||||
// Note that this call blocks on the the UI websocket handle.
|
|
||||||
|
// Note that this call blocks on the the UI websocket handle for up to 'timeOutMs'.
|
||||||
// See ui:ws:exec().
|
// See ui:ws:exec().
|
||||||
rc_t exec( handle_t h, void* execCbArg=nullptr );
|
rc_t exec( handle_t h, unsigned timeOutMs, void* execCbArg=nullptr );
|
||||||
|
|
||||||
bool isShuttingDown( handle_t h );
|
bool isShuttingDown( handle_t h );
|
||||||
void report( handle_t h );
|
void report( handle_t h );
|
||||||
|
void hardwareReport( handle_t h );
|
||||||
void realTimeReport( handle_t h );
|
void realTimeReport( handle_t h );
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Thread
|
// Thread
|
||||||
@ -229,6 +232,11 @@ namespace cw
|
|||||||
unsigned midiDevicePortIndex( handle_t h, unsigned devIdx, bool inputFl, const char* portName );
|
unsigned midiDevicePortIndex( handle_t h, unsigned devIdx, bool inputFl, const char* portName );
|
||||||
rc_t midiDeviceSend( handle_t h, unsigned devIdx, unsigned portIdx, uint8_t status, uint8_t d0, uint8_t d1 );
|
rc_t midiDeviceSend( handle_t h, unsigned devIdx, unsigned portIdx, uint8_t status, uint8_t d0, uint8_t d1 );
|
||||||
|
|
||||||
|
unsigned midiDeviceMaxBufferMsgCount( handle_t h );
|
||||||
|
const midi::ch_msg_t* midiDeviceBuffer( handle_t h, unsigned& msgCntRef );
|
||||||
|
rc_t midiDeviceClearBuffer( handle_t h, unsigned msgCnt );
|
||||||
|
|
||||||
|
|
||||||
rc_t midiOpenMidiFile( handle_t h, unsigned devIdx, unsigned portIdx, const char* fname );
|
rc_t midiOpenMidiFile( handle_t h, unsigned devIdx, unsigned portIdx, const char* fname );
|
||||||
rc_t midiLoadMsgPacket( handle_t h, const midi::packet_t& pkt ); // Note: Set devIdx/portIdx via pkt.devIdx/pkt.portIdx
|
rc_t midiLoadMsgPacket( handle_t h, const midi::packet_t& pkt ); // Note: Set devIdx/portIdx via pkt.devIdx/pkt.portIdx
|
||||||
unsigned midiMsgCount( handle_t h, unsigned devIdx, unsigned portIdx );
|
unsigned midiMsgCount( handle_t h, unsigned devIdx, unsigned portIdx );
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
@ -1024,8 +1025,16 @@ cw::rc_t cw::io::audio_midi::main( const object_t* cfg )
|
|||||||
// execute the io framework
|
// execute the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
const unsigned wsTimeOutMs = 50;
|
||||||
sleepMs(50);
|
time::spec_t t0 = time::current_time();
|
||||||
|
|
||||||
|
exec(app.ioH,wsTimeOutMs);
|
||||||
|
|
||||||
|
time::spec_t t1 = time::current_time();
|
||||||
|
unsigned dMs = time::elapsedMs(t0,t1);
|
||||||
|
|
||||||
|
if( dMs < wsTimeOutMs )
|
||||||
|
sleepMs(wsTimeOutMs-dMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
@ -580,8 +581,16 @@ cw::rc_t cw::audio_midi_app::main( const object_t* cfg )
|
|||||||
// execute the io framework
|
// execute the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
const unsigned wsTimeOutMs = 50;
|
||||||
sleepMs(50);
|
time::spec_t t0 = time::current_time();
|
||||||
|
|
||||||
|
exec(app.ioH,wsTimeOutMs);
|
||||||
|
|
||||||
|
time::spec_t t1 = time::current_time();
|
||||||
|
unsigned dMs = time::elapsedMs(t0,t1);
|
||||||
|
|
||||||
|
if( dMs < wsTimeOutMs )
|
||||||
|
sleepMs(wsTimeOutMs-dMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
|
74
cwIoFlow.cpp
74
cwIoFlow.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
@ -8,6 +9,8 @@
|
|||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwVectOps.h"
|
#include "cwVectOps.h"
|
||||||
#include "cwMtx.h"
|
#include "cwMtx.h"
|
||||||
|
#include "cwTime.h"
|
||||||
|
#include "cwMidiDecls.h"
|
||||||
|
|
||||||
#include "cwDspTypes.h"
|
#include "cwDspTypes.h"
|
||||||
#include "cwFlowDecl.h"
|
#include "cwFlowDecl.h"
|
||||||
@ -95,10 +98,13 @@ namespace cw
|
|||||||
{
|
{
|
||||||
unsigned devN = 0;
|
unsigned devN = 0;
|
||||||
|
|
||||||
//devN += midiDeviceCount(p->ioH);
|
|
||||||
devN += socketCount(p->ioH);
|
devN += socketCount(p->ioH);
|
||||||
devN += serialDeviceCount(p->ioH);
|
devN += serialDeviceCount(p->ioH);
|
||||||
|
|
||||||
|
unsigned midiDevN = midiDeviceCount(p->ioH);
|
||||||
|
for(unsigned i=0; i<midiDevN; ++i)
|
||||||
|
devN += midiDevicePortCount(p->ioH,i,true) + midiDevicePortCount(p->ioH,i,false);
|
||||||
|
|
||||||
for(unsigned i=0; i<p->audioGroupN; ++i)
|
for(unsigned i=0; i<p->audioGroupN; ++i)
|
||||||
devN += p->audioGroupA[i].iDeviceN + p->audioGroupA[i].oDeviceN;
|
devN += p->audioGroupA[i].iDeviceN + p->audioGroupA[i].oDeviceN;
|
||||||
|
|
||||||
@ -109,7 +115,6 @@ namespace cw
|
|||||||
{
|
{
|
||||||
dev->ioDevIdx = ioDevIdx;
|
dev->ioDevIdx = ioDevIdx;
|
||||||
dev->ioDevId = audioDeviceUserId( p->ioH, ioDevIdx );
|
dev->ioDevId = audioDeviceUserId( p->ioH, ioDevIdx );
|
||||||
dev->abuf.base = nullptr;
|
|
||||||
dev->abuf.srate = audioDeviceSampleRate( p->ioH, ioDevIdx );
|
dev->abuf.srate = audioDeviceSampleRate( p->ioH, ioDevIdx );
|
||||||
dev->abuf.chN = audioDeviceChannelCount( p->ioH, ioDevIdx, inOrOutFl );
|
dev->abuf.chN = audioDeviceChannelCount( p->ioH, ioDevIdx, inOrOutFl );
|
||||||
dev->abuf.frameN = dspFrameCnt;
|
dev->abuf.frameN = dspFrameCnt;
|
||||||
@ -146,18 +151,33 @@ namespace cw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _send_midi_triple( flow::external_device_t* dev, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
void _setup_device_cfg( flow::external_device_t* d, const char* devLabel, unsigned ioDevId, unsigned typeId, unsigned flags )
|
|
||||||
{
|
{
|
||||||
d->label = devLabel;
|
return midiDeviceSend(((io_flow_t*)dev->reserved)->ioH, dev->ioDevIdx, dev->ioPortIdx, status |= ch, d0, d1);
|
||||||
d->ioDevId = ioDevId;
|
}
|
||||||
|
|
||||||
|
void _setup_device_cfg( io_flow_t* p, flow::external_device_t* d, const char* devLabel, unsigned ioDevIdx, unsigned typeId, unsigned flags, const char* midiPortLabel=nullptr, unsigned midiPortIdx=kInvalidIdx )
|
||||||
|
{
|
||||||
|
d->reserved = p;
|
||||||
|
d->devLabel = devLabel;
|
||||||
|
d->portLabel = midiPortLabel;
|
||||||
d->typeId = typeId;
|
d->typeId = typeId;
|
||||||
d->flags = flags;
|
d->flags = flags;
|
||||||
|
d->ioDevIdx = ioDevIdx;
|
||||||
|
d->ioPortIdx = midiPortIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setup_midi_device_cfg( io_flow_t* p, flow::external_device_t* d, const char* devLabel, unsigned ioDevIdx, unsigned flags, unsigned ioMidiPortIdx )
|
||||||
|
{
|
||||||
|
const char* midiPortLabel = io::midiDevicePortName(p->ioH,ioDevIdx, flags & flow::kInFl ? true : false,ioMidiPortIdx);
|
||||||
|
_setup_device_cfg( p, d, devLabel, ioDevIdx, flow::kMidiDevTypeId, flags, midiPortLabel, ioMidiPortIdx );
|
||||||
|
d->u.m.maxMsgCnt = io::midiDeviceMaxBufferMsgCount(p->ioH);
|
||||||
|
d->u.m.sendTripleFunc = _send_midi_triple;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setup_audio_device_cfg( io_flow_t* p, flow::external_device_t* d, audio_group_t* ag, audio_dev_t* ad, unsigned flags )
|
void _setup_audio_device_cfg( io_flow_t* p, flow::external_device_t* d, audio_group_t* ag, audio_dev_t* ad, unsigned flags )
|
||||||
{
|
{
|
||||||
_setup_device_cfg( d, io::audioDeviceLabel(p->ioH,ad->ioDevIdx), ad->ioDevId, flow::kAudioDevTypeId, flags );
|
_setup_device_cfg( p, d, io::audioDeviceLabel(p->ioH,ad->ioDevIdx), ad->ioDevIdx, flow::kAudioDevTypeId, flags );
|
||||||
|
|
||||||
// Each audio device is given a flow::abuf to hold incoming or outgoing audio.
|
// Each audio device is given a flow::abuf to hold incoming or outgoing audio.
|
||||||
// This buffer also allows the 'audio_in' and 'audio_out' flow procs to configure themselves.
|
// This buffer also allows the 'audio_in' and 'audio_out' flow procs to configure themselves.
|
||||||
@ -175,15 +195,25 @@ namespace cw
|
|||||||
|
|
||||||
// get serial devices
|
// get serial devices
|
||||||
for(unsigned di=0; i<p->deviceN && di<serialDeviceCount(p->ioH); ++di,++i)
|
for(unsigned di=0; i<p->deviceN && di<serialDeviceCount(p->ioH); ++di,++i)
|
||||||
_setup_device_cfg( p->deviceA + i, io::serialDeviceLabel(p->ioH,di), io::serialDeviceId(p->ioH,di), flow::kSerialDevTypeId, flow::kInFl | flow::kOutFl );
|
_setup_device_cfg( p, p->deviceA + i, io::serialDeviceLabel(p->ioH,di), di, flow::kSerialDevTypeId, flow::kInFl | flow::kOutFl );
|
||||||
|
|
||||||
// get midi devices
|
|
||||||
//for(unsigned di=0; i<p->deviceN && di<midiDeviceCount(p->ioH); ++di,++i)
|
|
||||||
// _setup_device_cfg( p->deviceA + i, io::midiDeviceLabel(p->ioH,di), di, flow::kMidiDevTypeId, flow::kInFl | flow::kOutFl );
|
|
||||||
|
|
||||||
// get sockets
|
// get sockets
|
||||||
for(unsigned di=0; i<p->deviceN && di<socketCount(p->ioH); ++di,++i)
|
for(unsigned di=0; i<p->deviceN && di<socketCount(p->ioH); ++di,++i)
|
||||||
_setup_device_cfg( p->deviceA + i, io::socketLabel(p->ioH,di), io::socketUserId(p->ioH,di), flow::kSocketDevTypeId, flow::kInFl | flow::kOutFl );
|
_setup_device_cfg( p, p->deviceA + i, io::socketLabel(p->ioH,di), di, flow::kSocketDevTypeId, flow::kInFl | flow::kOutFl );
|
||||||
|
|
||||||
|
|
||||||
|
// get midi devices
|
||||||
|
for(unsigned di=0; i<p->deviceN && di<midiDeviceCount(p->ioH); ++di)
|
||||||
|
{
|
||||||
|
// input port setup
|
||||||
|
for(unsigned pi=0; pi<midiDevicePortCount(p->ioH,di,true); ++pi,++i)
|
||||||
|
_setup_midi_device_cfg( p, p->deviceA + i, io::midiDeviceName(p->ioH,di), di, flow::kInFl, pi);
|
||||||
|
|
||||||
|
// output port setup
|
||||||
|
for(unsigned pi=0; pi<midiDevicePortCount(p->ioH,di,false); ++pi,++i)
|
||||||
|
_setup_midi_device_cfg( p, p->deviceA + i, io::midiDeviceName(p->ioH,di), di, flow::kOutFl, pi);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// get the audio devices
|
// get the audio devices
|
||||||
@ -198,6 +228,9 @@ namespace cw
|
|||||||
_setup_audio_device_cfg( p, p->deviceA + i, ag, ag->oDeviceA + di, flow::kOutFl );
|
_setup_audio_device_cfg( p, p->deviceA + i, ag, ag->oDeviceA + di, flow::kOutFl );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assert( i == p->deviceN );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _device_index_to_abuf( io_flow_t* p, unsigned ioGroupIdx, unsigned ioDevIdx, unsigned inOrOutFl, flow::abuf_t*& abuf_ref )
|
rc_t _device_index_to_abuf( io_flow_t* p, unsigned ioGroupIdx, unsigned ioDevIdx, unsigned inOrOutFl, flow::abuf_t*& abuf_ref )
|
||||||
@ -254,6 +287,18 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
flow::abuf_t* abuf = nullptr;
|
flow::abuf_t* abuf = nullptr;
|
||||||
|
|
||||||
|
// Get an array of incoming MIDI events which have occurred since the last call to 'io::midiDeviceBuffer()'
|
||||||
|
unsigned midiBufMsgCnt = 0;
|
||||||
|
const midi::ch_msg_t* midiBuf = midiDeviceBuffer(p->ioH,midiBufMsgCnt);
|
||||||
|
|
||||||
|
// Give each MIDI input device a pointer to the incoming MIDI msgs
|
||||||
|
for(unsigned i=0; i<p->deviceN; ++i)
|
||||||
|
if( p->deviceA[i].typeId == flow::kMidiDevTypeId && cwIsFlag(p->deviceA[i].flags,flow::kInFl) )
|
||||||
|
{
|
||||||
|
p->deviceA[i].u.m.msgArray = midiBuf;
|
||||||
|
p->deviceA[i].u.m.msgCnt = midiBufMsgCnt;
|
||||||
|
}
|
||||||
|
|
||||||
// if there is incoming (recorded) audio
|
// if there is incoming (recorded) audio
|
||||||
if( m.iBufChCnt > 0 )
|
if( m.iBufChCnt > 0 )
|
||||||
{
|
{
|
||||||
@ -318,6 +363,9 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
// Drop the MIDI messages that were processed on this call.
|
||||||
|
midiDeviceClearBuffer(p->ioH,midiBufMsgCnt);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwKeyboard.h"
|
#include "cwKeyboard.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
@ -118,8 +119,16 @@ cw::rc_t cw::min_test( const object_t* cfg )
|
|||||||
// execuite the io framework
|
// execuite the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
const unsigned wsTimeOutMs = 50;
|
||||||
sleepMs(500);
|
time::spec_t t0 = time::current_time();
|
||||||
|
|
||||||
|
exec(app.ioH,wsTimeOutMs);
|
||||||
|
|
||||||
|
time::spec_t t1 = time::current_time();
|
||||||
|
unsigned dMs = time::elapsedMs(t0,t1);
|
||||||
|
|
||||||
|
if( dMs < wsTimeOutMs )
|
||||||
|
sleepMs(wsTimeOutMs-dMs);
|
||||||
|
|
||||||
if( isKeyWaiting() )
|
if( isKeyWaiting() )
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwNumericConvert.h"
|
#include "cwNumericConvert.h"
|
||||||
@ -47,6 +48,7 @@ namespace cw
|
|||||||
kPanelDivId = 1000,
|
kPanelDivId = 1000,
|
||||||
kQuitBtnId,
|
kQuitBtnId,
|
||||||
kIoReportBtnId,
|
kIoReportBtnId,
|
||||||
|
kIoHwReportBtnId,
|
||||||
kIoRtReportBtnId,
|
kIoRtReportBtnId,
|
||||||
kPresetReportBtnId,
|
kPresetReportBtnId,
|
||||||
kMRP_ReportBtnId,
|
kMRP_ReportBtnId,
|
||||||
@ -161,11 +163,12 @@ namespace cw
|
|||||||
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
|
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
|
||||||
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
|
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
|
||||||
{ kPanelDivId, kIoReportBtnId, "ioReportBtnId" },
|
{ kPanelDivId, kIoReportBtnId, "ioReportBtnId" },
|
||||||
{ kPanelDivId, kIoRtReportBtnId,"ioRtReportBtnId" },
|
{ kPanelDivId, kIoHwReportBtnId, "ioHwReportBtnId" },
|
||||||
|
{ kPanelDivId, kIoRtReportBtnId, "ioRtReportBtnId" },
|
||||||
|
{ kPanelDivId, kMRP_ReportBtnId, "MRP_ReportBtnId" },
|
||||||
|
{ kPanelDivId, kPresetReportBtnId, "presetReportBtnId" },
|
||||||
{ kPanelDivId, kNetPrintBtnId, "netPrintBtnId" },
|
{ kPanelDivId, kNetPrintBtnId, "netPrintBtnId" },
|
||||||
{ kPanelDivId, kReportBtnId, "reportBtnId" },
|
{ kPanelDivId, kReportBtnId, "reportBtnId" },
|
||||||
{ kPanelDivId, kPresetReportBtnId, "presetReportBtnId" },
|
|
||||||
{ kPanelDivId, kMRP_ReportBtnId, "MRP_ReportBtnId" },
|
|
||||||
{ kPanelDivId, kLatencyBtnId, "latencyBtnId" },
|
{ kPanelDivId, kLatencyBtnId, "latencyBtnId" },
|
||||||
|
|
||||||
{ kPanelDivId, kStartBtnId, "startBtnId" },
|
{ kPanelDivId, kStartBtnId, "startBtnId" },
|
||||||
@ -307,7 +310,7 @@ namespace cw
|
|||||||
const char* record_fn_ext;
|
const char* record_fn_ext;
|
||||||
const char* record_backup_dir;
|
const char* record_backup_dir;
|
||||||
|
|
||||||
const char* scoreFn;
|
//const char* scoreFn;
|
||||||
const object_t* perfDirL;
|
const object_t* perfDirL;
|
||||||
const char* velTableFname;
|
const char* velTableFname;
|
||||||
const char* velTableBackupDir;
|
const char* velTableBackupDir;
|
||||||
@ -386,6 +389,7 @@ namespace cw
|
|||||||
|
|
||||||
const char* dflt_perf_label;
|
const char* dflt_perf_label;
|
||||||
unsigned dflt_perf_app_id;
|
unsigned dflt_perf_app_id;
|
||||||
|
unsigned run_dur_secs;
|
||||||
|
|
||||||
|
|
||||||
} app_t;
|
} app_t;
|
||||||
@ -401,13 +405,13 @@ namespace cw
|
|||||||
app->record_fn = argv[i+1];
|
app->record_fn = argv[i+1];
|
||||||
goto found_fl;
|
goto found_fl;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if( textCompare(argv[i],"score_fn") == 0 )
|
if( textCompare(argv[i],"score_fn") == 0 )
|
||||||
{
|
{
|
||||||
app->scoreFn = argv[i+1];
|
app->scoreFn = argv[i+1];
|
||||||
goto found_fl;
|
goto found_fl;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if( textCompare(argv[i],"beg_play_loc") == 0 )
|
if( textCompare(argv[i],"beg_play_loc") == 0 )
|
||||||
{
|
{
|
||||||
string_to_number( argv[i+1], app->beg_play_loc );
|
string_to_number( argv[i+1], app->beg_play_loc );
|
||||||
@ -449,7 +453,7 @@ namespace cw
|
|||||||
if((rc = params_cfgRef->getv( "record_dir", app->record_dir,
|
if((rc = params_cfgRef->getv( "record_dir", app->record_dir,
|
||||||
"record_fn", app->record_fn,
|
"record_fn", app->record_fn,
|
||||||
"record_fn_ext", app->record_fn_ext,
|
"record_fn_ext", app->record_fn_ext,
|
||||||
"score_fn", app->scoreFn,
|
//"score_fn", app->scoreFn,
|
||||||
"perfDirL", app->perfDirL,
|
"perfDirL", app->perfDirL,
|
||||||
"flow_proc_dict_fn", flow_proc_dict_fn,
|
"flow_proc_dict_fn", flow_proc_dict_fn,
|
||||||
"midi_play_record", app->midi_play_record_cfg,
|
"midi_play_record", app->midi_play_record_cfg,
|
||||||
@ -460,6 +464,7 @@ namespace cw
|
|||||||
"beg_play_loc", app->beg_play_loc,
|
"beg_play_loc", app->beg_play_loc,
|
||||||
"end_play_loc", app->end_play_loc,
|
"end_play_loc", app->end_play_loc,
|
||||||
"dflt_perf_label", app->dflt_perf_label,
|
"dflt_perf_label", app->dflt_perf_label,
|
||||||
|
"run_dur_secs", app->run_dur_secs,
|
||||||
"live_mode_fl", app->useLiveMidiFl,
|
"live_mode_fl", app->useLiveMidiFl,
|
||||||
"enable_recording_fl", app->enableRecordFl,
|
"enable_recording_fl", app->enableRecordFl,
|
||||||
"midi_record_dir", midi_record_dir,
|
"midi_record_dir", midi_record_dir,
|
||||||
@ -482,11 +487,13 @@ namespace cw
|
|||||||
_apply_command_line_args(app,argc,argv);
|
_apply_command_line_args(app,argc,argv);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
if((app->scoreFn = filesys::expandPath( app->scoreFn )) == nullptr )
|
if((app->scoreFn = filesys::expandPath( app->scoreFn )) == nullptr )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The score file name is invalid.");
|
rc = cwLogError(kInvalidArgRC,"The score file name is invalid.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if((app->record_dir = filesys::expandPath(app->record_dir)) == nullptr )
|
if((app->record_dir = filesys::expandPath(app->record_dir)) == nullptr )
|
||||||
{
|
{
|
||||||
@ -565,10 +572,10 @@ namespace cw
|
|||||||
|
|
||||||
void _log_output_func( void* arg, unsigned level, const char* text )
|
void _log_output_func( void* arg, unsigned level, const char* text )
|
||||||
{
|
{
|
||||||
app_t* app = (app_t*)arg;
|
//app_t* app = (app_t*)arg;
|
||||||
unsigned logUuId = uiFindElementUuId( app->ioH, kLogId);
|
//unsigned logUuId = uiFindElementUuId( app->ioH, kLogId);
|
||||||
|
|
||||||
uiSetLogLine( app->ioH, logUuId, text );
|
//uiSetLogLine( app->ioH, logUuId, text );
|
||||||
log::defaultOutput(nullptr,level,text);
|
log::defaultOutput(nullptr,level,text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +606,7 @@ namespace cw
|
|||||||
|
|
||||||
mem::release((char*&)app.record_backup_dir);
|
mem::release((char*&)app.record_backup_dir);
|
||||||
mem::release((char*&)app.record_dir);
|
mem::release((char*&)app.record_dir);
|
||||||
mem::release((char*&)app.scoreFn);
|
//mem::release((char*&)app.scoreFn);
|
||||||
mem::release(app.midiRecordDir);
|
mem::release(app.midiRecordDir);
|
||||||
mem::release(app.midiLoadFname);
|
mem::release(app.midiLoadFname);
|
||||||
vtbl::destroy(app.vtH);
|
vtbl::destroy(app.vtH);
|
||||||
@ -725,6 +732,7 @@ namespace cw
|
|||||||
char* perf_fname = nullptr;
|
char* perf_fname = nullptr;
|
||||||
char* meta_fname = nullptr;
|
char* meta_fname = nullptr;
|
||||||
bool skip_fl = false;
|
bool skip_fl = false;
|
||||||
|
|
||||||
// create the performance recording file path
|
// create the performance recording file path
|
||||||
if((perf_fname = filesys::makeFn(dir,fname,nullptr,recording_folder,nullptr)) == nullptr )
|
if((perf_fname = filesys::makeFn(dir,fname,nullptr,recording_folder,nullptr)) == nullptr )
|
||||||
{
|
{
|
||||||
@ -796,8 +804,11 @@ namespace cw
|
|||||||
|
|
||||||
mem::release(meta_fname);
|
mem::release(meta_fname);
|
||||||
mem::release(perf_fname);
|
mem::release(perf_fname);
|
||||||
return rc;
|
|
||||||
|
|
||||||
|
if( meta_cfg != nullptr )
|
||||||
|
meta_cfg->free();
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _parse_perf_recording_dir( app_t* app, const char* dir, const char* fname, const object_t* velTblCfg )
|
rc_t _parse_perf_recording_dir( app_t* app, const char* dir, const char* fname, const object_t* velTblCfg )
|
||||||
@ -1000,9 +1011,9 @@ namespace cw
|
|||||||
// apply the fragment defined gain settings
|
// apply the fragment defined gain settings
|
||||||
if( app->ioFlowH.isValid() )
|
if( app->ioFlowH.isValid() )
|
||||||
{
|
{
|
||||||
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wet_in_gain", "gain", flow::kAnyChIdx, (dsp::real_t)frag->igain );
|
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wet_in_gain", "gain", flow::kAnyChIdx, (dsp::coeff_t)frag->igain );
|
||||||
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wet_out_gain","gain", flow::kAnyChIdx, (dsp::real_t)frag->ogain );
|
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wet_out_gain","gain", flow::kAnyChIdx, (dsp::coeff_t)frag->ogain );
|
||||||
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wd_bal", "in", flow::kAnyChIdx, (dsp::real_t)frag->wetDryGain );
|
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wd_bal", "in", flow::kAnyChIdx, (dsp::coeff_t)frag->wetDryGain );
|
||||||
|
|
||||||
// activate the cross-fade
|
// activate the cross-fade
|
||||||
io_flow::begin_cross_fade( app->ioFlowH, frag->fadeOutMs );
|
io_flow::begin_cross_fade( app->ioFlowH, frag->fadeOutMs );
|
||||||
@ -1158,8 +1169,6 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if( preset_sel::track_loc( app->psH, loc, f ) )
|
if( preset_sel::track_loc( app->psH, loc, f ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("Loc:%i\n",loc);
|
|
||||||
_apply_preset( app, loc, (const perf_score::event_t*)msg_arg, f );
|
_apply_preset( app, loc, (const perf_score::event_t*)msg_arg, f );
|
||||||
|
|
||||||
if( f != nullptr )
|
if( f != nullptr )
|
||||||
@ -1879,7 +1888,7 @@ namespace cw
|
|||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
if(rc != kOkRC )
|
if(rc != kOkRC )
|
||||||
rc = cwLogError(rc,"Preset control index '%i' create failed.");
|
rc = cwLogError(rc,"Preset control index '%i' create failed.", preset_idx);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1966,7 +1975,7 @@ namespace cw
|
|||||||
// read the preset data file
|
// read the preset data file
|
||||||
if((rc = preset_sel::read( app->psH, fn)) != kOkRC )
|
if((rc = preset_sel::read( app->psH, fn)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"File write failed on preset select.");
|
rc = cwLogError(rc,"File read failed on preset select.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2284,7 +2293,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _do_load_perf_score( app_t* app, const char* perf_fn, const vel_tbl_t* vtA=nullptr, unsigned vtN=0 )
|
rc_t _do_load_perf_score( app_t* app, const char* perf_fn, const vel_tbl_t* vtA=nullptr, unsigned vtN=0, unsigned beg_loc=score_parse::kInvalidLocId, unsigned end_loc=score_parse::kInvalidLocId )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned midiEventN = 0;
|
unsigned midiEventN = 0;
|
||||||
@ -2330,8 +2339,8 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
// set the UI begin/end play to the locations of the newly loaded performance
|
// set the UI begin/end play to the locations of the newly loaded performance
|
||||||
if( !lockLoctnFl )
|
if( !lockLoctnFl )
|
||||||
{
|
{
|
||||||
app->end_play_loc = app->maxPerfLoc;
|
app->end_play_loc = end_loc==score_parse::kInvalidLocId ? app->maxPerfLoc : end_loc;
|
||||||
app->beg_play_loc = app->minPerfLoc;
|
app->beg_play_loc = beg_loc==score_parse::kInvalidLocId ? app->minPerfLoc : beg_loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the master range of the play beg/end number widgets
|
// Update the master range of the play beg/end number widgets
|
||||||
@ -2397,7 +2406,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
printf("Loading:%s\n",prp->fname );
|
printf("Loading:%s\n",prp->fname );
|
||||||
|
|
||||||
// load the requested performance
|
// load the requested performance
|
||||||
if((rc = _do_load_perf_score(app,prp->fname,prp->vel_tblA, prp->vel_tblN)) != kOkRC )
|
if((rc = _do_load_perf_score(app,prp->fname,prp->vel_tblA, prp->vel_tblN, prp->beg_loc, prp->end_loc)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"The performance load failed.");
|
rc = cwLogError(kSyntaxErrorRC,"The performance load failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -2906,7 +2915,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( app->ioFlowH.isValid() )
|
if( app->ioFlowH.isValid() )
|
||||||
if((rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, inst_label, var_label, flow::kAnyChIdx, (dsp::real_t)value )) != kOkRC )
|
if((rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, inst_label, var_label, flow::kAnyChIdx, (dsp::coeff_t)value )) != kOkRC )
|
||||||
rc = cwLogError(rc,"Master value send failed on %s.%s.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label));
|
rc = cwLogError(rc,"Master value send failed on %s.%s.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label));
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -3001,7 +3010,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( m.value->tid == ui::kDoubleTId && app->ioFlowH.isValid() )
|
if( m.value->tid == ui::kDoubleTId && app->ioFlowH.isValid() )
|
||||||
rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, "sd", var_label, flow::kAnyChIdx, (dsp::real_t)m.value->u.d );
|
rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, "sd", var_label, flow::kAnyChIdx, (dsp::coeff_t)m.value->u.d );
|
||||||
|
|
||||||
if(rc != kOkRC )
|
if(rc != kOkRC )
|
||||||
rc = cwLogError(rc,"Attempt to set a spec-dist variable '%s'",var_label );
|
rc = cwLogError(rc,"Attempt to set a spec-dist variable '%s'",var_label );
|
||||||
@ -3012,7 +3021,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
rc_t _on_live_midi_checkbox( app_t* app, bool useLiveMidiFl )
|
rc_t _on_live_midi_checkbox( app_t* app, bool useLiveMidiFl )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
dsp::real_t value;
|
dsp::ftime_t value;
|
||||||
|
|
||||||
if( useLiveMidiFl )
|
if( useLiveMidiFl )
|
||||||
{
|
{
|
||||||
@ -3032,7 +3041,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( app->ioFlowH.isValid() )
|
if( app->ioFlowH.isValid() )
|
||||||
if((rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, "sync_delay", "delayMs", flow::kAnyChIdx, (dsp::real_t)value )) != kOkRC )
|
if((rc = io_flow::set_variable_value( app->ioFlowH, flow_cross::kAllDestId, "sync_delay", "delayMs", flow::kAnyChIdx, (dsp::ftime_t)value )) != kOkRC )
|
||||||
rc = cwLogError(rc,"Error setting sync delay 'flow' value.");
|
rc = cwLogError(rc,"Error setting sync delay 'flow' value.");
|
||||||
|
|
||||||
|
|
||||||
@ -3097,8 +3106,12 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
|||||||
io::report( app->ioH );
|
io::report( app->ioH );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kIoHwReportBtnId:
|
||||||
|
io::hardwareReport( app->ioH );
|
||||||
|
break;
|
||||||
|
|
||||||
case kIoRtReportBtnId:
|
case kIoRtReportBtnId:
|
||||||
io::realTimeReport(app->ioH);
|
io::realTimeReport( app->ioH );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kNetPrintBtnId:
|
case kNetPrintBtnId:
|
||||||
@ -3698,6 +3711,7 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, int argc, const char* ar
|
|||||||
unsigned bigMapN = mapN + vtMapN;
|
unsigned bigMapN = mapN + vtMapN;
|
||||||
ui::appIdMap_t bigMap[ bigMapN ];
|
ui::appIdMap_t bigMap[ bigMapN ];
|
||||||
double sysSampleRate = 0;
|
double sysSampleRate = 0;
|
||||||
|
time::spec_t start_time = time::current_time();
|
||||||
|
|
||||||
for(unsigned i=0; i<mapN; ++i)
|
for(unsigned i=0; i<mapN; ++i)
|
||||||
bigMap[i] = mapA[i];
|
bigMap[i] = mapA[i];
|
||||||
@ -3822,18 +3836,27 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, int argc, const char* ar
|
|||||||
// execute the io framework
|
// execute the io framework
|
||||||
while( !io::isShuttingDown(app.ioH))
|
while( !io::isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
//time::spec_t t0;
|
const unsigned wsTimeOutMs = 50;
|
||||||
//time::get(t0);
|
time::spec_t t0 = time::current_time();
|
||||||
|
|
||||||
|
unsigned timeOutMs = app.psNextFrag != nullptr ? 0 : wsTimeOutMs;
|
||||||
|
|
||||||
// This call may block on the websocket handle.
|
// This call may block on the websocket handle.
|
||||||
io::exec(app.ioH);
|
io::exec(app.ioH,timeOutMs);
|
||||||
|
|
||||||
//unsigned dMs = time::elapsedMs(t0);
|
time::spec_t t1 = time::current_time();
|
||||||
//if( dMs < 50 && app.psNextFrag == nullptr )
|
unsigned dMs = time::elapsedMs(t0,t1);
|
||||||
//{
|
|
||||||
// sleepMs( 50-dMs );
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
if( dMs < wsTimeOutMs && app.psNextFrag == nullptr )
|
||||||
|
{
|
||||||
|
sleepMs( wsTimeOutMs-dMs );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( app.run_dur_secs != 0 && time::elapsedMs( start_time )/1000 > app.run_dur_secs )
|
||||||
|
{
|
||||||
|
printf("Run duration expired (%i secs). Shutting down.\n",app.run_dur_secs);
|
||||||
|
io::stop(app.ioH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop the io framework
|
// stop the io framework
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
13
cwIoTest.cpp
13
cwIoTest.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
@ -308,8 +309,16 @@ cw::rc_t cw::io::test( const object_t* cfg )
|
|||||||
// execuite the io framework
|
// execuite the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
const unsigned wsTimeOutMs = 50;
|
||||||
sleepMs(50);
|
time::spec_t t0 = time::current_time();
|
||||||
|
|
||||||
|
exec(app.ioH,wsTimeOutMs);
|
||||||
|
|
||||||
|
time::spec_t t1 = time::current_time();
|
||||||
|
unsigned dMs = time::elapsedMs(t0,t1);
|
||||||
|
|
||||||
|
if( dMs < wsTimeOutMs )
|
||||||
|
sleepMs(wsTimeOutMs-dMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
15
cwLex.cpp
15
cwLex.cpp
@ -3,7 +3,8 @@
|
|||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwObject.h"
|
||||||
#include "cwLex.h"
|
#include "cwLex.h"
|
||||||
|
|
||||||
|
|
||||||
@ -853,7 +854,7 @@ namespace cw
|
|||||||
//)
|
//)
|
||||||
|
|
||||||
//(
|
//(
|
||||||
rc_t test()
|
rc_t test( const test::test_args_t& args )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned tid = kInvalidId;
|
unsigned tid = kInvalidId;
|
||||||
@ -866,7 +867,9 @@ namespace cw
|
|||||||
"/* block \n"
|
"/* block \n"
|
||||||
"comment */"
|
"comment */"
|
||||||
"\"quoted string\""
|
"\"quoted string\""
|
||||||
"ident1"
|
"ident1 "
|
||||||
|
"1234.56f"
|
||||||
|
"345u"
|
||||||
" // last line comment";
|
" // last line comment";
|
||||||
|
|
||||||
// initialize a lexer with a buffer of text
|
// initialize a lexer with a buffer of text
|
||||||
@ -884,7 +887,7 @@ namespace cw
|
|||||||
while( (tid = lex::getNextToken(h)) != kEofLexTId )
|
while( (tid = lex::getNextToken(h)) != kEofLexTId )
|
||||||
{
|
{
|
||||||
// print information about each token
|
// print information about each token
|
||||||
cwLogInfo("%i %i %s '%.*s' (%i) ",
|
cwLogInfo("ln:%i col:%i tok:%s '%.*s' len:%i ",
|
||||||
lex::currentLineNumber(h),
|
lex::currentLineNumber(h),
|
||||||
lex::currentColumnNumber(h),
|
lex::currentColumnNumber(h),
|
||||||
lex::idToLabel(h,tid),
|
lex::idToLabel(h,tid),
|
||||||
@ -899,11 +902,9 @@ namespace cw
|
|||||||
int iv = lex::tokenInt(h);
|
int iv = lex::tokenInt(h);
|
||||||
double dv = lex::tokenDouble(h);
|
double dv = lex::tokenDouble(h);
|
||||||
|
|
||||||
cwLogInfo("%i %f",iv,dv);
|
cwLogInfo("Number: int:%i dbl:%f unsigned:%i float:%i",iv,dv,tokenIsUnsigned(h),tokenIsSinglePrecision(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
cwLogInfo("\n");
|
|
||||||
|
|
||||||
// handle errors
|
// handle errors
|
||||||
if( tid == kErrorLexTId )
|
if( tid == kErrorLexTId )
|
||||||
{
|
{
|
||||||
|
2
cwLex.h
2
cwLex.h
@ -129,7 +129,7 @@ namespace cw
|
|||||||
const char* idToLabel( handle_t h, unsigned typeId );
|
const char* idToLabel( handle_t h, unsigned typeId );
|
||||||
|
|
||||||
// Lexer testing stub.
|
// Lexer testing stub.
|
||||||
rc_t test( );
|
rc_t test( const test::test_args_t& args );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
#include "cwLib.h"
|
#include "cwLib.h"
|
||||||
|
36
cwLog.cpp
36
cwLog.cpp
@ -2,6 +2,7 @@
|
|||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
|
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const c
|
|||||||
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t returnCode, const char* fmt, ... )
|
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t returnCode, const char* fmt, ... )
|
||||||
{
|
{
|
||||||
rc_t rc = returnCode;
|
rc_t rc = returnCode;
|
||||||
if( level >= _handleToPtr(h)->level )
|
if( level >= _handleToPtr(h)->level || level == kPrint_LogLevel )
|
||||||
{
|
{
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl,fmt);
|
va_start(vl,fmt);
|
||||||
@ -146,6 +147,29 @@ unsigned cw::log::flags( handle_t h )
|
|||||||
return p->flags;
|
return p->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* cw::log::outputCbArg( handle_t h )
|
||||||
|
{
|
||||||
|
log_t* p = _handleToPtr(h);
|
||||||
|
return p->outCbArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::log::logOutputCbFunc_t cw::log::outputCb( handle_t h )
|
||||||
|
{
|
||||||
|
log_t* p = _handleToPtr(h);
|
||||||
|
return p->outCbFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* cw::log::formatCbArg( handle_t h )
|
||||||
|
{
|
||||||
|
log_t* p = _handleToPtr(h);
|
||||||
|
return p->fmtCbArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::log::logFormatCbFunc_t cw::log::formatCb( handle_t h )
|
||||||
|
{
|
||||||
|
log_t* p = _handleToPtr(h);
|
||||||
|
return p->fmtCbFunc;
|
||||||
|
}
|
||||||
|
|
||||||
void cw::log::setOutputCb( handle_t h, logOutputCbFunc_t outFunc, void* outCbArg )
|
void cw::log::setOutputCb( handle_t h, logOutputCbFunc_t outFunc, void* outCbArg )
|
||||||
{
|
{
|
||||||
@ -164,13 +188,7 @@ void cw::log::setFormatCb( handle_t h, logFormatCbFunc_t fmtFunc, void* fmtCbArg
|
|||||||
|
|
||||||
|
|
||||||
const char* cw::log::levelToLabel( unsigned level )
|
const char* cw::log::levelToLabel( unsigned level )
|
||||||
{
|
{ return idToLabel(logLevelLabelArray,level,kInvalid_LogLevel); }
|
||||||
const char* label;
|
|
||||||
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
|
|
||||||
label = "<unknown>";
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -220,7 +238,7 @@ void cw::log::defaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* ou
|
|||||||
|
|
||||||
|
|
||||||
// don't print the function,file,line when this is an 'info' msg.
|
// don't print the function,file,line when this is an 'info' msg.
|
||||||
if( level == kInfo_LogLevel )
|
if( level == kInfo_LogLevel || level == kPrint_LogLevel )
|
||||||
{
|
{
|
||||||
loStr = "";
|
loStr = "";
|
||||||
syStr = "";
|
syStr = "";
|
||||||
|
6
cwLog.h
6
cwLog.h
@ -39,6 +39,12 @@ namespace cw
|
|||||||
void setLevel( handle_t h, unsigned level );
|
void setLevel( handle_t h, unsigned level );
|
||||||
unsigned level( handle_t h );
|
unsigned level( handle_t h );
|
||||||
|
|
||||||
|
void* outputCbArg( handle_t h );
|
||||||
|
logOutputCbFunc_t outputCb( handle_t h );
|
||||||
|
|
||||||
|
void* formatCbArg( handle_t h );
|
||||||
|
logFormatCbFunc_t formatCb( handle_t h );
|
||||||
|
|
||||||
void setOutputCb( handle_t h, logOutputCbFunc_t outFunc, void* outCbArg );
|
void setOutputCb( handle_t h, logOutputCbFunc_t outFunc, void* outCbArg );
|
||||||
void setFormatCb( handle_t h, logFormatCbFunc_t fmtFunc, void* fmtCbArg );
|
void setFormatCb( handle_t h, logFormatCbFunc_t fmtFunc, void* fmtCbArg );
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ void cw::math::doubleToX80(double val, unsigned char rate[10])
|
|||||||
|
|
||||||
bool cw::math::isPowerOfTwo( unsigned x )
|
bool cw::math::isPowerOfTwo( unsigned x )
|
||||||
{
|
{
|
||||||
return !( (x < 2) || (x & (x-1)) );
|
return x==1 || (!( (x < 2) || (x & (x-1)) ));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned cw::math::nextPowerOfTwo( unsigned val )
|
unsigned cw::math::nextPowerOfTwo( unsigned val )
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
|
|
||||||
#include "cwThread.h"
|
#include "cwThread.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwMidi.h"
|
#include "cwMidi.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
@ -283,6 +284,7 @@ namespace cw
|
|||||||
time::spec_t ts;
|
time::spec_t ts;
|
||||||
ts.tv_sec = ev->time.time.tv_sec;
|
ts.tv_sec = ev->time.time.tv_sec;
|
||||||
ts.tv_nsec = ev->time.time.tv_nsec;
|
ts.tv_nsec = ev->time.time.tv_nsec;
|
||||||
|
|
||||||
parser::midiTriple(p->prvRcvPort->parserH, &ts, status | ch, d0, d1 );
|
parser::midiTriple(p->prvRcvPort->parserH, &ts, status | ch, d0, d1 );
|
||||||
|
|
||||||
p->prvTimeMicroSecs = microSecs1;
|
p->prvTimeMicroSecs = microSecs1;
|
||||||
@ -439,7 +441,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
assert(j<p->devArray[i].iPortCnt);
|
assert(j<p->devArray[i].iPortCnt);
|
||||||
p->devArray[i].iPortArray[j].inputFl = true;
|
p->devArray[i].iPortArray[j].inputFl = true;
|
||||||
p->devArray[i].iPortArray[j].nameStr = mem::duplStr(cwStringNullGuard(port));
|
p->devArray[i].iPortArray[j].nameStr = mem::duplStr(port==nullptr ? "<None>" : port);
|
||||||
p->devArray[i].iPortArray[j].alsa_type = type;
|
p->devArray[i].iPortArray[j].alsa_type = type;
|
||||||
p->devArray[i].iPortArray[j].alsa_cap = caps;
|
p->devArray[i].iPortArray[j].alsa_cap = caps;
|
||||||
p->devArray[i].iPortArray[j].alsa_addr = addr;
|
p->devArray[i].iPortArray[j].alsa_addr = addr;
|
||||||
@ -461,7 +463,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
assert(k<p->devArray[i].oPortCnt);
|
assert(k<p->devArray[i].oPortCnt);
|
||||||
p->devArray[i].oPortArray[k].inputFl = false;
|
p->devArray[i].oPortArray[k].inputFl = false;
|
||||||
p->devArray[i].oPortArray[k].nameStr = mem::duplStr(cwStringNullGuard(port));
|
p->devArray[i].oPortArray[k].nameStr = mem::duplStr(port==nullptr ? "<None>" : port);
|
||||||
p->devArray[i].oPortArray[k].alsa_type = type;
|
p->devArray[i].oPortArray[k].alsa_type = type;
|
||||||
p->devArray[i].oPortArray[k].alsa_cap = caps;
|
p->devArray[i].oPortArray[k].alsa_cap = caps;
|
||||||
p->devArray[i].oPortArray[k].alsa_addr = addr;
|
p->devArray[i].oPortArray[k].alsa_addr = addr;
|
||||||
@ -475,6 +477,11 @@ namespace cw
|
|||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The capabilities of some ports may not have been as expected
|
||||||
|
// decrease the in/out port count to account for these ports
|
||||||
|
p->devArray[i].iPortCnt = j;
|
||||||
|
p->devArray[i].oPortCnt = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
@ -736,7 +743,7 @@ const char* cw::midi::device::alsa::portName( handle_t h, unsigned devIdx,
|
|||||||
if( cwIsFlag(flags,kInMpFl) )
|
if( cwIsFlag(flags,kInMpFl) )
|
||||||
{
|
{
|
||||||
if( portIdx >= p->devArray[devIdx].iPortCnt )
|
if( portIdx >= p->devArray[devIdx].iPortCnt )
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return p->devArray[devIdx].iPortArray[portIdx].nameStr;
|
return p->devArray[devIdx].iPortArray[portIdx].nameStr;
|
||||||
}
|
}
|
||||||
@ -796,8 +803,11 @@ cw::rc_t cw::midi::device::alsa::send( handle_t h, unsigned devIdx, unsigned po
|
|||||||
snd_seq_ev_set_direct(&ev);
|
snd_seq_ev_set_direct(&ev);
|
||||||
snd_seq_ev_set_fixed(&ev);
|
snd_seq_ev_set_fixed(&ev);
|
||||||
|
|
||||||
|
uint8_t status_wo_ch = status;
|
||||||
|
if( midi::isChStatus(status) )
|
||||||
|
status_wo_ch = status & 0xf0;
|
||||||
|
|
||||||
switch( status & 0xf0 )
|
switch( status_wo_ch )
|
||||||
{
|
{
|
||||||
case kNoteOffMdId:
|
case kNoteOffMdId:
|
||||||
ev.type = SND_SEQ_EVENT_NOTEOFF;
|
ev.type = SND_SEQ_EVENT_NOTEOFF;
|
||||||
@ -854,8 +864,32 @@ cw::rc_t cw::midi::device::alsa::send( handle_t h, unsigned devIdx, unsigned po
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kSysRtClockMdId:
|
||||||
|
ev.type = SND_SEQ_EVENT_CLOCK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSysRtStartMdId:
|
||||||
|
ev.type =SND_SEQ_EVENT_START;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSysRtContMdId:
|
||||||
|
ev.type = SND_SEQ_EVENT_CONTINUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSysRtStopMdId:
|
||||||
|
ev.type = SND_SEQ_EVENT_STOP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSysRtSenseMdId:
|
||||||
|
ev.type = SND_SEQ_EVENT_SENSING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSysRtResetMdId:
|
||||||
|
ev.type = SND_SEQ_EVENT_RESET;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rc = _cmMpErrMsg1(kInvalidArgRC,0,"Cannot send an invalid MIDI status byte:0x%x.",status & 0xf0);
|
rc = _cmMpErrMsg1(kInvalidArgRC,0,"Cannot send an invalid MIDI status byte:0x%x.",status);
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct packet_str
|
typedef struct packet_str
|
||||||
{
|
{
|
||||||
void* cbArg; // Application supplied reference value
|
//void* cbArg; // Application supplied reference value
|
||||||
unsigned devIdx; // The device the msg originated from
|
unsigned devIdx; // The device the msg originated from
|
||||||
unsigned portIdx; // The port index on the source device
|
unsigned portIdx; // The port index on the source device
|
||||||
msg_t* msgArray; // Pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL
|
msg_t* msgArray; // Pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL
|
||||||
@ -25,8 +25,19 @@ namespace cw
|
|||||||
unsigned msgCnt; // Count of mdMsg records or sys-ex bytes
|
unsigned msgCnt; // Count of mdMsg records or sys-ex bytes
|
||||||
} packet_t;
|
} packet_t;
|
||||||
|
|
||||||
typedef void (*cbFunc_t)( const packet_t* pktArray, unsigned pktCnt );
|
typedef void (*cbFunc_t)( void* cbArg, const packet_t* pktArray, unsigned pktCnt );
|
||||||
|
|
||||||
|
typedef struct ch_msg_str
|
||||||
|
{
|
||||||
|
time::spec_t timeStamp;
|
||||||
|
unsigned devIdx; // The device the msg originated from
|
||||||
|
unsigned portIdx; // The port index on the source device
|
||||||
|
unsigned uid; // application specified id
|
||||||
|
uint8_t ch; // midi channel
|
||||||
|
uint8_t status; // midi status byte (channel has been removed)
|
||||||
|
uint8_t d0; // midi data byte 0
|
||||||
|
uint8_t d1; // midi data byte 1
|
||||||
|
} ch_msg_t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
120
cwMidiDevice.cpp
120
cwMidiDevice.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
@ -55,6 +56,11 @@ namespace cw
|
|||||||
unsigned long long last_posn_micros;
|
unsigned long long last_posn_micros;
|
||||||
time::spec_t start_time;
|
time::spec_t start_time;
|
||||||
|
|
||||||
|
ch_msg_t* buf;
|
||||||
|
unsigned bufN;
|
||||||
|
std::atomic<unsigned> buf_ii;
|
||||||
|
std::atomic<unsigned> buf_oi;
|
||||||
|
|
||||||
} device_t;
|
} device_t;
|
||||||
|
|
||||||
device_t* _handleToPtr( handle_t h )
|
device_t* _handleToPtr( handle_t h )
|
||||||
@ -102,8 +108,11 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
destroy(p->alsaDevH);
|
destroy(p->alsaDevH);
|
||||||
destroy(p->fileDevH);
|
destroy(p->fileDevH);
|
||||||
|
|
||||||
|
mem::release(p->buf);
|
||||||
mem::release(p);
|
mem::release(p);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
@ -173,6 +182,45 @@ namespace cw
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _callback( void* cbArg, const packet_t* pktArray, unsigned pktCnt )
|
||||||
|
{
|
||||||
|
device_t* p = (device_t*)cbArg;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<pktCnt; ++i)
|
||||||
|
{
|
||||||
|
const packet_t* pkt = pktArray + i;
|
||||||
|
if( pkt->msgArray != nullptr )
|
||||||
|
{
|
||||||
|
unsigned ii = p->buf_ii.load();
|
||||||
|
unsigned oi = p->buf_oi.load();
|
||||||
|
for(unsigned j=0; j<pkt->msgCnt; ++j)
|
||||||
|
{
|
||||||
|
ch_msg_t* m = p->buf + ii;
|
||||||
|
m->devIdx = pkt->devIdx;
|
||||||
|
m->portIdx = pkt->portIdx;
|
||||||
|
m->timeStamp = pkt->msgArray[j].timeStamp;
|
||||||
|
m->uid = pkt->msgArray[j].uid;
|
||||||
|
m->ch = pkt->msgArray[j].ch;
|
||||||
|
m->status = pkt->msgArray[j].status;
|
||||||
|
m->d0 = pkt->msgArray[j].d0;
|
||||||
|
m->d1 = pkt->msgArray[j].d1;
|
||||||
|
|
||||||
|
ii = (ii+1 == p->bufN ? 0 : ii+1);
|
||||||
|
if( ii == oi )
|
||||||
|
{
|
||||||
|
cwLogError(kBufTooSmallRC,"The MIDI device buffer is full %i.",p->bufN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->buf_ii.store(ii);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->cbFunc != nullptr )
|
||||||
|
p->cbFunc(p->cbArg,pktArray,pktCnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // device
|
} // device
|
||||||
} // midi
|
} // midi
|
||||||
@ -188,7 +236,9 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
|
|||||||
const char* appNameStr,
|
const char* appNameStr,
|
||||||
const char* fileDevName,
|
const char* fileDevName,
|
||||||
unsigned fileDevReadAheadMicros,
|
unsigned fileDevReadAheadMicros,
|
||||||
unsigned parserBufByteCnt )
|
unsigned parserBufByteCnt,
|
||||||
|
bool enableBufFl,
|
||||||
|
unsigned bufferMsgCnt )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
rc_t rc1 = kOkRC;
|
rc_t rc1 = kOkRC;
|
||||||
@ -198,7 +248,11 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
|
|||||||
|
|
||||||
device_t* p = mem::allocZ<device_t>();
|
device_t* p = mem::allocZ<device_t>();
|
||||||
|
|
||||||
if((rc = create( p->alsaDevH, cbFunc, cbArg, parserBufByteCnt, appNameStr )) != kOkRC )
|
if((rc = create( p->alsaDevH,
|
||||||
|
enableBufFl ? _callback : cbFunc,
|
||||||
|
enableBufFl ? p : cbArg,
|
||||||
|
parserBufByteCnt,
|
||||||
|
appNameStr )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"ALSA MIDI device create failed.");
|
rc = cwLogError(rc,"ALSA MIDI device create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -206,16 +260,29 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
|
|||||||
|
|
||||||
p->alsa_dev_cnt = count(p->alsaDevH);
|
p->alsa_dev_cnt = count(p->alsaDevH);
|
||||||
|
|
||||||
if((rc = create( p->fileDevH, cbFunc, cbArg, p->alsa_dev_cnt, filePortLabelA, max_file_cnt, fileDevName, fileDevReadAheadMicros )) != kOkRC )
|
if((rc = create( p->fileDevH,
|
||||||
|
enableBufFl ? _callback : cbFunc,
|
||||||
|
enableBufFl ? p : cbArg,
|
||||||
|
p->alsa_dev_cnt,
|
||||||
|
filePortLabelA,
|
||||||
|
max_file_cnt,
|
||||||
|
fileDevName,
|
||||||
|
fileDevReadAheadMicros )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"MIDI file device create failed.");
|
rc = cwLogError(rc,"MIDI file device create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->cbFunc = cbFunc;
|
||||||
|
p->cbArg = cbArg;
|
||||||
p->file_dev_cnt = count(p->fileDevH);
|
p->file_dev_cnt = count(p->fileDevH);
|
||||||
p->total_dev_cnt = p->alsa_dev_cnt + p->file_dev_cnt;
|
p->total_dev_cnt = p->alsa_dev_cnt + p->file_dev_cnt;
|
||||||
p->alsaPollfdA = pollFdArray(p->alsaDevH,p->alsaPollfdN);
|
p->alsaPollfdA = pollFdArray(p->alsaDevH,p->alsaPollfdN);
|
||||||
p->fileDevStateId = kStoppedStateId;
|
p->fileDevStateId = kStoppedStateId;
|
||||||
|
p->buf = mem::allocZ<ch_msg_t>( bufferMsgCnt );
|
||||||
|
p->bufN = bufferMsgCnt;
|
||||||
|
p->buf_ii.store(0);
|
||||||
|
p->buf_oi.store(0);
|
||||||
|
|
||||||
if((rc = thread::create(p->threadH,
|
if((rc = thread::create(p->threadH,
|
||||||
_thread_func,
|
_thread_func,
|
||||||
@ -257,6 +324,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
|
|||||||
const char* fileDevName = "file_dev";
|
const char* fileDevName = "file_dev";
|
||||||
unsigned fileDevReadAheadMicros = 3000;
|
unsigned fileDevReadAheadMicros = 3000;
|
||||||
unsigned parseBufByteCnt = 1024;
|
unsigned parseBufByteCnt = 1024;
|
||||||
|
bool enableBufFl = false;
|
||||||
|
unsigned bufMsgCnt = 0;
|
||||||
const object_t* file_ports = nullptr;
|
const object_t* file_ports = nullptr;
|
||||||
const object_t* port = nullptr;
|
const object_t* port = nullptr;
|
||||||
|
|
||||||
@ -264,6 +333,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
|
|||||||
"fileDevName",fileDevName,
|
"fileDevName",fileDevName,
|
||||||
"fileDevReadAheadMicros",fileDevReadAheadMicros,
|
"fileDevReadAheadMicros",fileDevReadAheadMicros,
|
||||||
"parseBufByteCnt",parseBufByteCnt,
|
"parseBufByteCnt",parseBufByteCnt,
|
||||||
|
"enableBufFl",enableBufFl,
|
||||||
|
"bufferMsgCnt",bufMsgCnt,
|
||||||
"file_ports",file_ports)) != kOkRC )
|
"file_ports",file_ports)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"MIDI port parse args. failed.");
|
rc = cwLogError(rc,"MIDI port parse args. failed.");
|
||||||
@ -290,7 +361,7 @@ cw::rc_t cw::midi::device::create( handle_t& h,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = create(h,cbFunc,cbArg,labelArray,fpi,appNameStr,fileDevName,fileDevReadAheadMicros,parseBufByteCnt);
|
rc = create(h,cbFunc,cbArg,labelArray,fpi,appNameStr,fileDevName,fileDevReadAheadMicros,parseBufByteCnt,enableBufFl,bufMsgCnt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +516,7 @@ const char* cw::midi::device::portName( handle_t h, unsigned devIdx, unsigned
|
|||||||
cwLogError(kInvalidArgRC,"The device index %i is not valid.");
|
cwLogError(kInvalidArgRC,"The device index %i is not valid.");
|
||||||
|
|
||||||
if( name == nullptr )
|
if( name == nullptr )
|
||||||
cwLogError(kOpFailRC,"The access to port name on device index %i port index %i failed.",devIdx,portIdx);
|
cwLogError(kOpFailRC,"The access to %s port name on device index %i port index %i failed.",flags & kInMpFl ? "input" : "output", devIdx,portIdx);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -591,6 +662,43 @@ errLabel:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned cw::midi::device::maxBufferMsgCount( handle_t h )
|
||||||
|
{
|
||||||
|
device_t* p = _handleToPtr(h);
|
||||||
|
return p->bufN;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cw::midi::ch_msg_t* cw::midi::device::getBuffer( handle_t h, unsigned& msgCntRef )
|
||||||
|
{
|
||||||
|
device_t* p = _handleToPtr(h);
|
||||||
|
unsigned ii = p->buf_ii.load();
|
||||||
|
unsigned oi = p->buf_oi.load();
|
||||||
|
ch_msg_t* m = nullptr;
|
||||||
|
|
||||||
|
msgCntRef = ii >= oi ? ii-oi : p->bufN - oi;
|
||||||
|
|
||||||
|
if( msgCntRef > 0 )
|
||||||
|
m = p->buf + oi;
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::midi::device::clearBuffer( handle_t h, unsigned msgCnt )
|
||||||
|
{
|
||||||
|
if( msgCnt > 0 )
|
||||||
|
{
|
||||||
|
device_t* p = _handleToPtr(h);
|
||||||
|
unsigned oi = p->buf_oi.load();
|
||||||
|
|
||||||
|
oi = (oi + msgCnt) % p->bufN;
|
||||||
|
|
||||||
|
p->buf_oi.store(oi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::midi::device::start( handle_t h )
|
cw::rc_t cw::midi::device::start( handle_t h )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -669,6 +777,8 @@ cw::rc_t cw::midi::device::report( handle_t h )
|
|||||||
|
|
||||||
report(h,tbH);
|
report(h,tbH);
|
||||||
|
|
||||||
|
printf("%s\n",text(tbH));
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
destroy(tbH);
|
destroy(tbH);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -30,7 +30,9 @@ namespace cw
|
|||||||
const char* appNameStr,
|
const char* appNameStr,
|
||||||
const char* fileDevName = "file_dev",
|
const char* fileDevName = "file_dev",
|
||||||
unsigned fileDevReadAheadMicros = 3000,
|
unsigned fileDevReadAheadMicros = 3000,
|
||||||
unsigned parserBufByteCnt = 1024 );
|
unsigned parserBufByteCnt = 1024,
|
||||||
|
bool enableBufFl = false, // Enable buffer to hold all incoming msg's until RT thread can pick them up.
|
||||||
|
unsigned bufferMsgCnt = 4096); // Count of messages in input buffer.
|
||||||
|
|
||||||
rc_t create( handle_t& h,
|
rc_t create( handle_t& h,
|
||||||
cbFunc_t cbFunc,
|
cbFunc_t cbFunc,
|
||||||
@ -57,6 +59,10 @@ namespace cw
|
|||||||
rc_t seekToMsg( handle_t h, unsigned devIdx, unsigned portIdx, unsigned msgIdx );
|
rc_t seekToMsg( handle_t h, unsigned devIdx, unsigned portIdx, unsigned msgIdx );
|
||||||
rc_t setEndMsg( handle_t h, unsigned devIdx, unsigned portidx, unsigned msgIdx );
|
rc_t setEndMsg( handle_t h, unsigned devIdx, unsigned portidx, unsigned msgIdx );
|
||||||
|
|
||||||
|
unsigned maxBufferMsgCount( handle_t h ); // max number of msg's which will ever be returned in a buffer
|
||||||
|
const ch_msg_t* getBuffer( handle_t h, unsigned& msgCntRef );
|
||||||
|
rc_t clearBuffer( handle_t h, unsigned msgCnt );
|
||||||
|
|
||||||
rc_t start( handle_t h );
|
rc_t start( handle_t h );
|
||||||
rc_t stop( handle_t h );
|
rc_t stop( handle_t h );
|
||||||
rc_t pause( handle_t h, bool pause_fl );
|
rc_t pause( handle_t h, bool pause_fl );
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
@ -86,7 +87,7 @@ namespace cw
|
|||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _test_callback( const packet_t* pktArray, unsigned pktCnt )
|
void _test_callback( void* cbArg, const packet_t* pktArray, unsigned pktCnt )
|
||||||
{
|
{
|
||||||
unsigned i,j;
|
unsigned i,j;
|
||||||
time::spec_t cur_time = time::current_time();
|
time::spec_t cur_time = time::current_time();
|
||||||
@ -95,7 +96,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
const packet_t* p = pktArray + i;
|
const packet_t* p = pktArray + i;
|
||||||
|
|
||||||
test_t* t = (test_t*)p->cbArg;
|
test_t* t = (test_t*)cbArg;
|
||||||
|
|
||||||
for(j=0; j<p->msgCnt; ++j)
|
for(j=0; j<p->msgCnt; ++j)
|
||||||
if( p->msgArray != NULL )
|
if( p->msgArray != NULL )
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
@ -428,13 +429,12 @@ namespace cw
|
|||||||
if( p->cbFunc != nullptr )
|
if( p->cbFunc != nullptr )
|
||||||
{
|
{
|
||||||
packet_t pkt = {};
|
packet_t pkt = {};
|
||||||
pkt.cbArg = p->cbArg;
|
|
||||||
pkt.devIdx = p->base_dev_idx;
|
pkt.devIdx = p->base_dev_idx;
|
||||||
pkt.portIdx = file_idx;
|
pkt.portIdx = file_idx;
|
||||||
pkt.msgArray = msgA;
|
pkt.msgArray = msgA;
|
||||||
pkt.msgCnt = msgN;
|
pkt.msgCnt = msgN;
|
||||||
|
|
||||||
p->cbFunc( &pkt, 1 );
|
p->cbFunc( p->cbArg, &pkt, 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwMidi.h"
|
#include "cwMidi.h"
|
||||||
@ -58,8 +59,8 @@ namespace cw
|
|||||||
cbRecd_t* c = p->cbChain;
|
cbRecd_t* c = p->cbChain;
|
||||||
for(; c!=NULL; c=c->linkPtr)
|
for(; c!=NULL; c=c->linkPtr)
|
||||||
{
|
{
|
||||||
pkt->cbArg = c->cbDataPtr;
|
//pkt->cbArg = c->cbDataPtr;
|
||||||
c->cbFunc( pkt, pktCnt );
|
c->cbFunc( c->cbDataPtr, pkt, pktCnt );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +103,19 @@ namespace cw
|
|||||||
// get a pointer to the next msg in the buffer
|
// get a pointer to the next msg in the buffer
|
||||||
msg_t* msgPtr = (msg_t*)(p->buf + p->bufIdx);
|
msg_t* msgPtr = (msg_t*)(p->buf + p->bufIdx);
|
||||||
|
|
||||||
// fill the buffer msg
|
if( midi::isChStatus(p->status) )
|
||||||
msgPtr->timeStamp = *timeStamp;
|
{
|
||||||
msgPtr->status = p->status & 0xf0;
|
msgPtr->status = p->status & 0xf0;
|
||||||
msgPtr->ch = p->status & 0x0f;
|
msgPtr->ch = p->status & 0x0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msgPtr->status = p->status;
|
||||||
|
msgPtr->ch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill the buffer msg
|
||||||
|
msgPtr->timeStamp = *timeStamp;
|
||||||
msgPtr->uid = kInvalidId;
|
msgPtr->uid = kInvalidId;
|
||||||
|
|
||||||
switch( p->dataCnt )
|
switch( p->dataCnt )
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwVectOps.h"
|
#include "cwVectOps.h"
|
||||||
#include "cwMtx.h"
|
#include "cwMtx.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwMutex.h"
|
#include "cwMutex.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
@ -30,12 +31,15 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct node_str
|
typedef struct node_str
|
||||||
{
|
{
|
||||||
std::atomic<struct node_str*> next;
|
std::atomic<struct node_str*> next; // 0
|
||||||
block_t* block;
|
block_t* block; // 8
|
||||||
unsigned blobByteN;
|
unsigned blobByteN; // 16
|
||||||
|
unsigned pad; // 20-24 (mult. of 8)
|
||||||
// blob data follows
|
// blob data follows
|
||||||
} node_t;
|
} node_t;
|
||||||
|
|
||||||
|
static_assert( sizeof(node_t) % 8 == 0 );
|
||||||
|
|
||||||
typedef struct nbmpscq_str
|
typedef struct nbmpscq_str
|
||||||
{
|
{
|
||||||
uint8_t* mem; // Pointer to a single area of memory which holds all blocks.
|
uint8_t* mem; // Pointer to a single area of memory which holds all blocks.
|
||||||
@ -52,6 +56,8 @@ namespace cw
|
|||||||
|
|
||||||
node_t* tail; // first-out
|
node_t* tail; // first-out
|
||||||
|
|
||||||
|
node_t* peek;
|
||||||
|
|
||||||
} nbmpscq_t;
|
} nbmpscq_t;
|
||||||
|
|
||||||
nbmpscq_t* _handleToPtr( handle_t h )
|
nbmpscq_t* _handleToPtr( handle_t h )
|
||||||
@ -62,8 +68,18 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
if( p != nullptr )
|
if( p != nullptr )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
block_t* b = p->blockL;
|
||||||
|
while( b != nullptr )
|
||||||
|
{
|
||||||
|
block_t* b0 = b->link;
|
||||||
|
mem::release(b->buf);
|
||||||
|
mem::release(b);
|
||||||
|
b=b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
mem::release(p->stub);
|
mem::release(p->stub);
|
||||||
mem::release(p->mem);
|
|
||||||
mem::release(p);
|
mem::release(p);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -98,6 +114,22 @@ namespace cw
|
|||||||
p->cleanProcN += 1;
|
p->cleanProcN += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _init_blob( blob_t& b, node_t* node )
|
||||||
|
{
|
||||||
|
if( node == nullptr )
|
||||||
|
{
|
||||||
|
b.blob = nullptr;
|
||||||
|
b.blobByteN = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b.blob = (uint8_t*)(node+1);
|
||||||
|
b.blobByteN = node->blobByteN;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.rc = kOkRC;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct shared_str
|
typedef struct shared_str
|
||||||
{
|
{
|
||||||
@ -134,6 +166,19 @@ namespace cw
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _block_report( nbmpscq_t* p )
|
||||||
|
{
|
||||||
|
block_t* b = p->blockL;
|
||||||
|
for(; b!=nullptr; b=b->link)
|
||||||
|
{
|
||||||
|
bool full_fl = b->full_flag.load(std::memory_order_acquire);
|
||||||
|
unsigned index = b->index.load(std::memory_order_acquire);
|
||||||
|
int eleN = b->eleN.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
printf("full:%i idx:%i eleN:%i\n",full_fl,index,eleN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,7 +187,6 @@ cw::rc_t cw::nbmpscq::create( handle_t& hRef, unsigned initBlkN, unsigned blkByt
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
nbmpscq_t* p = nullptr;
|
nbmpscq_t* p = nullptr;
|
||||||
unsigned byteN = 0;
|
|
||||||
|
|
||||||
if((rc = destroy(hRef)) != kOkRC )
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -152,17 +196,17 @@ cw::rc_t cw::nbmpscq::create( handle_t& hRef, unsigned initBlkN, unsigned blkByt
|
|||||||
p->stub = mem::allocZ<node_t>();
|
p->stub = mem::allocZ<node_t>();
|
||||||
p->head = p->stub; // last-in
|
p->head = p->stub; // last-in
|
||||||
p->tail = p->stub; // first-out
|
p->tail = p->stub; // first-out
|
||||||
|
p->peek = nullptr;
|
||||||
p->cleanBlkN = 0;
|
p->cleanBlkN = 0;
|
||||||
|
|
||||||
p->blkN = initBlkN;
|
p->blkN = initBlkN;
|
||||||
p->blkByteN = blkByteN;
|
p->blkByteN = blkByteN;
|
||||||
byteN = initBlkN * (sizeof(block_t) + blkByteN );
|
|
||||||
p->mem = mem::allocZ<uint8_t>(byteN);
|
|
||||||
|
|
||||||
for(unsigned i=0; i<byteN; i+=(sizeof(block_t) + blkByteN))
|
for(unsigned i=0; i<initBlkN; ++i)
|
||||||
{
|
{
|
||||||
block_t* b = (block_t*)(p->mem+i);
|
block_t* b = mem::allocZ<block_t>();
|
||||||
b->buf = (uint8_t*)(b + 1);
|
b->buf = mem::allocZ<uint8_t>(blkByteN);
|
||||||
|
|
||||||
b->bufByteN = blkByteN;
|
b->bufByteN = blkByteN;
|
||||||
|
|
||||||
b->full_flag.store(false);
|
b->full_flag.store(false);
|
||||||
@ -171,6 +215,7 @@ cw::rc_t cw::nbmpscq::create( handle_t& hRef, unsigned initBlkN, unsigned blkByt
|
|||||||
|
|
||||||
b->link = p->blockL;
|
b->link = p->blockL;
|
||||||
p->blockL = b;
|
p->blockL = b;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hRef.set(p);
|
hRef.set(p);
|
||||||
@ -216,6 +261,17 @@ cw::rc_t cw::nbmpscq::push( handle_t h, const void* blob, unsigned blobByteN )
|
|||||||
|
|
||||||
unsigned nodeByteN = blobByteN + sizeof(node_t);
|
unsigned nodeByteN = blobByteN + sizeof(node_t);
|
||||||
|
|
||||||
|
// force the size of the node to be a multiple of 8
|
||||||
|
nodeByteN = ((nodeByteN-1) & 0xfffffff8) + 8;
|
||||||
|
|
||||||
|
// We will eventually be addressing node_t records stored in pre-allocated blocks
|
||||||
|
// of memory - be sure that they always begin on 8 byte alignment to conform
|
||||||
|
// to Intel standard.
|
||||||
|
assert( nodeByteN % 8 == 0 );
|
||||||
|
|
||||||
|
if( nodeByteN > p->blkByteN )
|
||||||
|
return cwLogError(kInvalidArgRC,"The blob size is too large:%i > %i.",nodeByteN,p->blkByteN);
|
||||||
|
|
||||||
for(; b!=nullptr; b=b->link)
|
for(; b!=nullptr; b=b->link)
|
||||||
{
|
{
|
||||||
if( b->full_flag.load(std::memory_order_acquire) == false )
|
if( b->full_flag.load(std::memory_order_acquire) == false )
|
||||||
@ -265,7 +321,13 @@ cw::rc_t cw::nbmpscq::push( handle_t h, const void* blob, unsigned blobByteN )
|
|||||||
{
|
{
|
||||||
// TODO: continue to iterate through the blocks waiting for the consumer
|
// TODO: continue to iterate through the blocks waiting for the consumer
|
||||||
// to make more space available.
|
// to make more space available.
|
||||||
|
//_block_report(p);
|
||||||
|
|
||||||
|
// BEWARE: BUG BUG BUG: Since the cwLog makes calls to cwWebSocket
|
||||||
|
// this error message, and subsequent error messages,
|
||||||
|
// will result in a recursive loop which will crash the program.
|
||||||
rc = cwLogError(kBufTooSmallRC,"NbMpScQueue overflow.");
|
rc = cwLogError(kBufTooSmallRC,"NbMpScQueue overflow.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -277,47 +339,99 @@ cw::nbmpscq::blob_t cw::nbmpscq::get( handle_t h )
|
|||||||
blob_t blob;
|
blob_t blob;
|
||||||
nbmpscq_t* p = _handleToPtr(h);
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
node_t* t = p->tail;
|
// We always access the tail element through tail->next.
|
||||||
node_t* n = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
node_t* node = p->tail->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||||
|
|
||||||
if( n == nullptr )
|
_init_blob( blob, node );
|
||||||
{
|
|
||||||
blob.blob = nullptr;
|
|
||||||
blob.blobByteN = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
blob.blob = (uint8_t*)(n+1);
|
|
||||||
blob.blobByteN = n->blobByteN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return blob;
|
return blob;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::nbmpscq::advance( handle_t h )
|
cw::nbmpscq::blob_t cw::nbmpscq::advance( handle_t h )
|
||||||
{
|
{
|
||||||
|
blob_t blob;
|
||||||
nbmpscq_t* p = _handleToPtr(h);
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
rc_t rc = kOkRC;
|
|
||||||
node_t* t = p->tail;
|
node_t* t = p->tail;
|
||||||
|
|
||||||
|
// We always access the tail element through tail->next.
|
||||||
node_t* next = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
node_t* next = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||||
|
|
||||||
|
// We always leave the last element on the queue to act as 'stub'.
|
||||||
if( next != nullptr )
|
if( next != nullptr )
|
||||||
{
|
{
|
||||||
p->tail = next;
|
p->tail = next;
|
||||||
|
|
||||||
block_t* b = next->block;
|
// first 'stub' will not have a valid block pointer
|
||||||
int eleN = b->eleN.fetch_add(-1,std::memory_order_acq_rel);
|
if( t->block != nullptr )
|
||||||
|
{
|
||||||
|
int eleN = t->block->eleN.fetch_add(-1,std::memory_order_acq_rel);
|
||||||
|
|
||||||
// next was valid and so eleN must be >= 1
|
// next was valid and so eleN must be >= 1
|
||||||
assert( eleN >= 1 );
|
assert( eleN >= 1 );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p->cleanBlkN.load(std::memory_order_relaxed) > 0 )
|
if( p->cleanBlkN.load(std::memory_order_relaxed) > 0 )
|
||||||
_clean(p);
|
_clean(p);
|
||||||
|
|
||||||
return rc;
|
|
||||||
|
_init_blob(blob,next);
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::nbmpscq::blob_t cw::nbmpscq::peek( handle_t h )
|
||||||
|
{
|
||||||
|
blob_t blob;
|
||||||
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
|
node_t* n = p->peek;
|
||||||
|
|
||||||
|
// if p->peek is not set ...
|
||||||
|
if( n == nullptr )
|
||||||
|
{
|
||||||
|
// ... then set it to the tail
|
||||||
|
n = p->tail->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_init_blob(blob,n);
|
||||||
|
|
||||||
|
if( n != nullptr )
|
||||||
|
p->peek = n->next.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ::cw::nbmpscq::peek_reset(handle_t h)
|
||||||
|
{
|
||||||
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
|
p->peek = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cw::nbmpscq::is_empty( handle_t h )
|
||||||
|
{
|
||||||
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
node_t* t = p->tail;
|
||||||
|
node_t* next = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||||
|
|
||||||
|
return next == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::nbmpscq::count( handle_t h )
|
||||||
|
{
|
||||||
|
nbmpscq_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
block_t* b = p->blockL;
|
||||||
|
int eleN = 0;
|
||||||
|
for(; b!=nullptr; b=b->link)
|
||||||
|
eleN += b->eleN.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
return eleN;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::nbmpscq::test( const object_t* cfg )
|
cw::rc_t cw::nbmpscq::test( const object_t* cfg )
|
||||||
|
@ -39,25 +39,53 @@ namespace cw
|
|||||||
|
|
||||||
rc_t destroy( handle_t& hRef );
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Producer Function
|
||||||
|
//
|
||||||
|
|
||||||
// push() is called by multiple producer threads to insert
|
// push() is called by multiple producer threads to insert
|
||||||
// an element in the queue. Note that the 'blob' is copied into
|
// an element in the queue. Note that the 'blob' is copied into
|
||||||
// the queue and therefore can be released by the caller.
|
// the queue and therefore can be released by the caller.
|
||||||
rc_t push( handle_t h, const void* blob, unsigned blobByteN );
|
rc_t push( handle_t h, const void* blob, unsigned blobByteN );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Consumer Functions
|
||||||
|
//
|
||||||
|
|
||||||
typedef struct blob_str
|
typedef struct blob_str
|
||||||
{
|
{
|
||||||
|
rc_t rc;
|
||||||
const void* blob;
|
const void* blob;
|
||||||
unsigned blobByteN;
|
unsigned blobByteN;
|
||||||
} blob_t;
|
} blob_t;
|
||||||
|
|
||||||
// get() is called by the single consumer thread to access the
|
// get() is called by the single consumer thread to access the
|
||||||
// current blob at the front of the queue. Note that this call
|
// oldest record in the queue. Note that this call
|
||||||
// does not change the state of the queue.
|
// does not change the state of the queue.
|
||||||
blob_t get( handle_t h );
|
blob_t get( handle_t h );
|
||||||
|
|
||||||
// advance() disposes of the blob at the front of the
|
// advance() disposes of the oldest blob in the
|
||||||
// queue and makes the next blob current.
|
// queue and makes the next blob current.
|
||||||
rc_t advance( handle_t h );
|
blob_t advance( handle_t h );
|
||||||
|
|
||||||
|
// The queue maintains a single internal iterator which the consumer
|
||||||
|
// may use to traverse stored records without removing them.
|
||||||
|
// The first call to peek() will return the oldest stored record.
|
||||||
|
// Each subsequent call to peek() will return the next stored record
|
||||||
|
// until no records are available - at which point blob_t.blob will be
|
||||||
|
// set to 'nullptr'. The following call will then revert to returning
|
||||||
|
// the oldest stored record.
|
||||||
|
blob_t peek( handle_t h );
|
||||||
|
|
||||||
|
// Reset peek to point to the oldest stored record.
|
||||||
|
void peek_reset( handle_t h );
|
||||||
|
|
||||||
|
// Return true if the queue is empty.
|
||||||
|
bool is_empty( handle_t h );
|
||||||
|
|
||||||
|
// Count of elements in the queue.
|
||||||
|
unsigned count( handle_t h );
|
||||||
|
|
||||||
rc_t test( const object_t* cfg );
|
rc_t test( const object_t* cfg );
|
||||||
|
|
||||||
|
165
cwObject.cpp
165
cwObject.cpp
@ -5,6 +5,7 @@
|
|||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwLex.h"
|
#include "cwLex.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwNumericConvert.h"
|
#include "cwNumericConvert.h"
|
||||||
@ -152,37 +153,37 @@ namespace cw
|
|||||||
void _objTypePrintIndent( const char* text, unsigned indent, const char* indentStr=" " )
|
void _objTypePrintIndent( const char* text, unsigned indent, const char* indentStr=" " )
|
||||||
{
|
{
|
||||||
for(unsigned i=0; i<indent; ++i)
|
for(unsigned i=0; i<indent; ++i)
|
||||||
printf("%s",indentStr);
|
cwLogPrint("%s",indentStr);
|
||||||
printf("%s",text);
|
cwLogPrint("%s",text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _objTypePrintChild( const object_t* o, print_ctx_t& c, const char* eolStr=",\n", const char* indentStr=" " )
|
void _objTypePrintChild( const object_t* o, print_ctx_t& c, const char* eolStr=",\n", const char* indentStr=" " )
|
||||||
{
|
{
|
||||||
_objTypePrintIndent(" ",c.indent,indentStr);
|
_objTypePrintIndent(" ",c.indent,indentStr);
|
||||||
o->type->print(o,c);
|
o->type->print(o,c);
|
||||||
printf("%s",eolStr);
|
cwLogPrint("%s",eolStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _objTypePrintNull( const object_t* o, print_ctx_t& c ) { printf("NULL "); }
|
void _objTypePrintNull( const object_t* o, print_ctx_t& c ) { cwLogPrint("NULL "); }
|
||||||
void _objTypePrintError( const object_t* o, print_ctx_t& c ) { printf("Error "); }
|
void _objTypePrintError( const object_t* o, print_ctx_t& c ) { cwLogPrint("Error "); }
|
||||||
void _objTypePrintChar( const object_t* o, print_ctx_t& c ) { printf("%c",o->u.c); }
|
void _objTypePrintChar( const object_t* o, print_ctx_t& c ) { cwLogPrint("%c",o->u.c); }
|
||||||
void _objTypePrintInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i8); }
|
void _objTypePrintInt8( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.i8); }
|
||||||
void _objTypePrintUInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u8); }
|
void _objTypePrintUInt8( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.u8); }
|
||||||
void _objTypePrintInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i16); }
|
void _objTypePrintInt16( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.i16); }
|
||||||
void _objTypePrintUInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u16); }
|
void _objTypePrintUInt16( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.u16); }
|
||||||
void _objTypePrintInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i32); }
|
void _objTypePrintInt32( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.i32); }
|
||||||
void _objTypePrintUInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u32); }
|
void _objTypePrintUInt32( const object_t* o, print_ctx_t& c ) { cwLogPrint("%i",o->u.u32); }
|
||||||
void _objTypePrintInt64( const object_t* o, print_ctx_t& c ) { printf("%lli", o->u.i64); }
|
void _objTypePrintInt64( const object_t* o, print_ctx_t& c ) { cwLogPrint("%lli", o->u.i64); }
|
||||||
void _objTypePrintUInt64( const object_t* o, print_ctx_t& c ) { printf("%lli", o->u.u64); }
|
void _objTypePrintUInt64( const object_t* o, print_ctx_t& c ) { cwLogPrint("%lli", o->u.u64); }
|
||||||
void _objTypePrintBool( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.b ? "true" : "false"); }
|
void _objTypePrintBool( const object_t* o, print_ctx_t& c ) { cwLogPrint("%s",o->u.b ? "true" : "false"); }
|
||||||
void _objTypePrintFloat( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.f); }
|
void _objTypePrintFloat( const object_t* o, print_ctx_t& c ) { cwLogPrint("%f",o->u.f); }
|
||||||
void _objTypePrintDouble( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.d); }
|
void _objTypePrintDouble( const object_t* o, print_ctx_t& c ) { cwLogPrint("%f",o->u.d); }
|
||||||
void _objTypePrintString( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.str); }
|
void _objTypePrintString( const object_t* o, print_ctx_t& c ) { cwLogPrint("%s",o->u.str); }
|
||||||
void _objTypePrintVect( const object_t* o, print_ctx_t& c ) { printf("<vect>"); }
|
void _objTypePrintVect( const object_t* o, print_ctx_t& c ) { cwLogPrint("<vect>"); }
|
||||||
void _objTypePrintPair( const object_t* o, print_ctx_t& c )
|
void _objTypePrintPair( const object_t* o, print_ctx_t& c )
|
||||||
{
|
{
|
||||||
o->u.children->type->print(o->u.children,c);
|
o->u.children->type->print(o->u.children,c);
|
||||||
printf(": ");
|
cwLogPrint(": ");
|
||||||
o->u.children->sibling->type->print(o->u.children->sibling,c);
|
o->u.children->sibling->type->print(o->u.children->sibling,c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -869,10 +870,16 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case lex::kRealLexTId:
|
case lex::kRealLexTId:
|
||||||
_objCreateValueNode( cnp, lex::tokenDouble(lexH), "real" );
|
if( tokenIsSinglePrecision(lexH) )
|
||||||
|
_objCreateValueNode( cnp, lex::tokenFloat(lexH),"float" );
|
||||||
|
else
|
||||||
|
_objCreateValueNode( cnp, lex::tokenDouble(lexH), "double" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case lex::kIntLexTId:
|
case lex::kIntLexTId:
|
||||||
|
if( tokenIsUnsigned(lexH) )
|
||||||
|
_objCreateValueNode( cnp, lex::tokenUInt(lexH), "uint" );
|
||||||
|
else
|
||||||
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -907,7 +914,7 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
|||||||
s[n] = 0;
|
s[n] = 0;
|
||||||
|
|
||||||
//char* v = mem::duplStr(lex::tokenText(lexH),lex::tokenCharCount(lexH));
|
//char* v = mem::duplStr(lex::tokenText(lexH),lex::tokenCharCount(lexH));
|
||||||
unsigned identFl = lexId == lex::kIdentLexTId ? kIdentFl : 0;
|
unsigned identFl = lexId != lex::kQStrLexTId ? kIdentFl : 0;
|
||||||
|
|
||||||
_objCreateValueNode<char*>( cnp, s, "string", identFl );
|
_objCreateValueNode<char*>( cnp, s, "string", identFl );
|
||||||
}
|
}
|
||||||
@ -1007,4 +1014,118 @@ cw::rc_t cw::objectToFile( const char* fn, const object_t* obj )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
rc_t _object_test_basic( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
cw::object_t* o = nullptr;
|
||||||
|
const char s [] = "{ a:1, b:2, c:[ 1.23, 4.56 ], d:true, e:false, f:true }";
|
||||||
|
|
||||||
|
int a = 0;
|
||||||
|
int b = 0;
|
||||||
|
const cw::object_t* c = nullptr;
|
||||||
|
bool d,e,f;
|
||||||
|
|
||||||
|
const unsigned bufN = 128;
|
||||||
|
char buf[bufN];
|
||||||
|
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
cw::object_t* oo = nullptr;
|
||||||
|
|
||||||
|
if((rc = cw::objectFromString(s,o)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
int v;
|
||||||
|
if((rc = o->get("b",v)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
cwLogPrint("value:%i\n",v);
|
||||||
|
|
||||||
|
o->print();
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = o->getv("a",a,"b",b)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
cwLogPrint("G: %i %i\n",a,b);
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = o->readv("a",0,a,
|
||||||
|
"b",0,b,
|
||||||
|
"c",cw::kOptFl | cw::kListTId,c,
|
||||||
|
"d",0,d,
|
||||||
|
"e",0,e,
|
||||||
|
"f",0,f)) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
cwLogPrint("R: %i %i : %i %i %i\n",a,b,d,e,f);
|
||||||
|
|
||||||
|
|
||||||
|
i = o->to_string(buf,bufN);
|
||||||
|
cwLogPrint("%i : %s\n",i, buf);
|
||||||
|
|
||||||
|
oo = o->duplicate();
|
||||||
|
|
||||||
|
oo->print();
|
||||||
|
|
||||||
|
oo->free();
|
||||||
|
|
||||||
|
|
||||||
|
o->free();
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _object_test_to_json( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
double v0[] = {1.23,2.34,3.45};
|
||||||
|
unsigned v0N = sizeof(v0)/sizeof(v0[0]);
|
||||||
|
int v1[] = {-1,0,1,2,3,4};
|
||||||
|
unsigned v1N = sizeof(v1)/sizeof(v1[0]);
|
||||||
|
|
||||||
|
cw::object_t* d = cw::newDictObject();
|
||||||
|
|
||||||
|
d->putv("A","Abc","B",1.234);
|
||||||
|
d->put_numeric_list("v0",v0,v0N);
|
||||||
|
d->put_numeric_list("v1",v1,v1N);
|
||||||
|
|
||||||
|
char* s = d->to_string();
|
||||||
|
cwLogPrint("%s\n",s);
|
||||||
|
cw::mem::release(s);
|
||||||
|
|
||||||
|
d->free();
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::object_test( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( textIsEqual(args.test_label,"basic") )
|
||||||
|
{
|
||||||
|
rc = _object_test_basic(args);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( textIsEqual(args.test_label,"to_json") )
|
||||||
|
{
|
||||||
|
rc = _object_test_to_json(args);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cwLogError(kInvalidArgRC,"Unknown test case module:%s test:%s.",args.module_label,args.test_label);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
120
cwObject.h
120
cwObject.h
@ -31,7 +31,8 @@ namespace cw
|
|||||||
kRootTId = 0x00100000,
|
kRootTId = 0x00100000,
|
||||||
|
|
||||||
kHexFl = 0x10000000,
|
kHexFl = 0x10000000,
|
||||||
kIdentFl = 0x20000000
|
kIdentFl = 0x20000000,
|
||||||
|
kOptFl = 0x40000000
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,12 +136,19 @@ namespace cw
|
|||||||
// Value containers are parents of leaf nodes. (A dictionary is not a value container because it's children are pairs with are not leaf nodes.)
|
// Value containers are parents of leaf nodes. (A dictionary is not a value container because it's children are pairs with are not leaf nodes.)
|
||||||
inline bool is_value_container() const { return type != nullptr && cwIsFlag(type->flags,kValueContainerFl); }
|
inline bool is_value_container() const { return type != nullptr && cwIsFlag(type->flags,kValueContainerFl); }
|
||||||
|
|
||||||
|
inline unsigned type_id() const { return type==nullptr ? (unsigned)kInvalidTId : type->id; }
|
||||||
|
|
||||||
// Containers have children and use the object.u.children pointer.
|
// Containers have children and use the object.u.children pointer.
|
||||||
inline bool is_container() const { return type != nullptr && cwIsFlag(type->flags,kContainerFl); }
|
inline bool is_container() const { return type != nullptr && cwIsFlag(type->flags,kContainerFl); }
|
||||||
inline bool is_pair() const { return type != nullptr && type->id == kPairTId; }
|
inline bool is_pair() const { return type != nullptr && type->id == kPairTId; }
|
||||||
inline bool is_dict() const { return type != nullptr && type->id == kDictTId; }
|
inline bool is_dict() const { return type != nullptr && type->id == kDictTId; }
|
||||||
inline bool is_list() const { return type != nullptr && type->id == kListTId; }
|
inline bool is_list() const { return type != nullptr && type->id == kListTId; }
|
||||||
inline bool is_string() const { return type != nullptr && (type->id == kStringTId || type->id == kCStringTId); }
|
inline bool is_string() const { return type != nullptr && (type->id == kStringTId || type->id == kCStringTId); }
|
||||||
|
inline bool is_unsigned_integer() const { return type->id==kCharTId || type->id==kUInt8TId || type->id==kUInt16TId || type->id==kUInt32TId || type->id==kUInt64TId; }
|
||||||
|
inline bool is_signed_integer() const { return type->id==kInt8TId || type->id==kInt16TId || type->id==kInt32TId || type->id==kInt64TId; }
|
||||||
|
inline bool is_floating_point() const { return type->id==kFloatTId || type->id==kDoubleTId; }
|
||||||
|
inline bool is_integer() const { return is_unsigned_integer() || is_signed_integer(); }
|
||||||
|
inline bool is_numeric() const { return is_integer() || is_floating_point(); }
|
||||||
inline bool is_type( unsigned tid ) const { return type != nullptr && type->id == tid; }
|
inline bool is_type( unsigned tid ) const { return type != nullptr && type->id == tid; }
|
||||||
|
|
||||||
rc_t value( void* dst, unsigned dstTypeId );
|
rc_t value( void* dst, unsigned dstTypeId );
|
||||||
@ -199,6 +207,114 @@ namespace cw
|
|||||||
const struct object_str* next_child_ele( const struct object_str* ele) const;
|
const struct object_str* next_child_ele( const struct object_str* ele) const;
|
||||||
struct object_str* next_child_ele( struct object_str* ele);
|
struct object_str* next_child_ele( struct object_str* ele);
|
||||||
|
|
||||||
|
typedef struct read_str
|
||||||
|
{
|
||||||
|
const char* label;
|
||||||
|
unsigned flags;
|
||||||
|
const struct read_str* link;
|
||||||
|
} read_t;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t read( const char* label, unsigned flags, T& v ) const
|
||||||
|
{
|
||||||
|
const struct object_str* o;
|
||||||
|
if((o = find(label, 0)) == nullptr )
|
||||||
|
{
|
||||||
|
if( cwIsNotFlag(flags, kOptFl) )
|
||||||
|
return cwLogError(kInvalidIdRC,"The pair label '%s' could not be found.",cwStringNullGuard(label));
|
||||||
|
|
||||||
|
return kEleNotFoundRC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags = cwClrFlag(flags,kOptFl);
|
||||||
|
if( flags && cwIsNotFlag(o->type->id,flags) )
|
||||||
|
return cwLogError(kInvalidDataTypeRC,"The field '%s' data type 0x%x does not match 0x%x.",cwStringNullGuard(label),o->type->id,flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return o->value(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _readv(const read_t* list) const
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
unsigned childN = child_count();
|
||||||
|
|
||||||
|
// for each child of this dict node
|
||||||
|
for(unsigned i=0; i<childN; ++i)
|
||||||
|
{
|
||||||
|
const struct object_str* child = child_ele(i);
|
||||||
|
const char* label = nullptr;
|
||||||
|
const read_t* r = list;
|
||||||
|
|
||||||
|
if( child == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kAssertFailRC,"A null child was encountered.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !child->is_pair() )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"A non-pair element was encountered inside a dictionary.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (label = child->pair_label()) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidStateRC,"A blank label was encountered as a dictionary label.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that this is a known label
|
||||||
|
// (all labels in the dictionary must be known - this prevents mispelled fields from being inadverently skipped during parsing)
|
||||||
|
for(; r!=nullptr; r=r->link)
|
||||||
|
if( strcmp(r->label,label) == 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( r == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"The unknown field '%s' was encountered.",cwStringNullGuard(label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// readv("label0",v0,"label1",v1, ... )
|
||||||
|
template< typename T0, typename T1, typename... ARGS >
|
||||||
|
rc_t _readv( const read_t* list, T0 label, unsigned flags, T1& valRef, ARGS&&... args ) const
|
||||||
|
{
|
||||||
|
rc_t rc = read(label,flags,valRef);
|
||||||
|
|
||||||
|
read_t r = { .label=label, .flags=flags, .link=list };
|
||||||
|
|
||||||
|
// if no error occurred ....
|
||||||
|
if( rc == kOkRC || (rc == kEleNotFoundRC && cwIsFlag(flags,kOptFl)))
|
||||||
|
rc = _readv(&r, std::forward<ARGS>(args)...); // ... recurse to find next label/value pair
|
||||||
|
else
|
||||||
|
rc = cwLogError(rc,"Object parse failed for the pair label:'%s'.",cwStringNullGuard(label));
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// readv("label0",flags0,v0,"label1",flags0,v1, ... )
|
||||||
|
// Use kOptFl for optional fields.
|
||||||
|
// Use kListTId and kDictTId to validate the type of container fields.
|
||||||
|
// In general it should not be necessary to validate numeric and string types because
|
||||||
|
// they are validated by virtue of being converted to the returned value.
|
||||||
|
template< typename T0, typename T1, typename... ARGS >
|
||||||
|
rc_t readv( T0 label, unsigned flags, T1& valRef, ARGS&&... args ) const
|
||||||
|
{ return _readv(nullptr, label,flags,valRef,args...); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set flag 'kRecurseFl' to recurse into the object in search of the value.
|
// Set flag 'kRecurseFl' to recurse into the object in search of the value.
|
||||||
// Set flag 'kOptionalFl' if the label is optional and may not exist.
|
// Set flag 'kOptionalFl' if the label is optional and may not exist.
|
||||||
@ -344,6 +460,8 @@ namespace cw
|
|||||||
|
|
||||||
rc_t objectToFile( const char* fn, const object_t* obj );
|
rc_t objectToFile( const char* fn, const object_t* obj );
|
||||||
|
|
||||||
|
rc_t object_test( const test::test_args_t& args );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,12 @@ namespace cw
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> object_t* _objSetLeafValue<float>( object_t* obj, float value )
|
||||||
|
{
|
||||||
|
obj->u.f = value;
|
||||||
|
obj->type = _objIdToType(kFloatTId);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
template<> object_t* _objSetLeafValue<double>( object_t* obj, double value )
|
template<> object_t* _objSetLeafValue<double>( object_t* obj, double value )
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwVectOps.h"
|
#include "cwVectOps.h"
|
||||||
|
#include "cwMidi.h"
|
||||||
|
#include "cwMidiDecls.h"
|
||||||
#include "cwFlowDecl.h"
|
#include "cwFlowDecl.h"
|
||||||
#include "cwPresetSel.h"
|
#include "cwPresetSel.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
|
|
||||||
#include "cwMidi.h"
|
|
||||||
#include "cwDynRefTbl.h"
|
#include "cwDynRefTbl.h"
|
||||||
#include "cwScoreParse.h"
|
#include "cwScoreParse.h"
|
||||||
#include "cwSfScore.h"
|
#include "cwSfScore.h"
|
||||||
@ -107,33 +109,47 @@ namespace cw
|
|||||||
|
|
||||||
rc_t _delete_fragment( preset_sel_t* p, unsigned fragId )
|
rc_t _delete_fragment( preset_sel_t* p, unsigned fragId )
|
||||||
{
|
{
|
||||||
frag_t* f0 = nullptr;
|
rc_t rc = kOkRC;
|
||||||
frag_t* f1 = p->fragL;
|
frag_t* f = p->fragL;
|
||||||
|
|
||||||
for(; f1!=nullptr; f1=f1->link)
|
for(; f!=nullptr; f=f->link)
|
||||||
{
|
{
|
||||||
if( f1->fragId == fragId )
|
if( f->fragId == fragId )
|
||||||
{
|
{
|
||||||
if( f0 == nullptr )
|
// if this is the first frag in the list
|
||||||
p->fragL = f1->link;
|
if( f->prev == nullptr )
|
||||||
|
p->fragL = f->link;
|
||||||
else
|
else
|
||||||
f0->link = f1->link;
|
{
|
||||||
|
|
||||||
for(unsigned i=0; i<f1->presetN; ++i)
|
// link the prev fragment to the next fragment
|
||||||
mem::release(f1->presetA[i].alt_str);
|
f->prev->link = f->link;
|
||||||
|
|
||||||
|
// dur of prev frag now include the dur of the deleted frag
|
||||||
|
f->prev->endLoc = f->endLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// link the next fragment back to the previous fragment
|
||||||
|
if( f->link != nullptr )
|
||||||
|
f->link->prev = f->prev;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<f->presetN; ++i)
|
||||||
|
mem::release(f->presetA[i].alt_str);
|
||||||
|
|
||||||
// release the fragment
|
// release the fragment
|
||||||
mem::release(f1->note);
|
mem::release(f->note);
|
||||||
mem::release(f1->presetA);
|
mem::release(f->presetA);
|
||||||
mem::release(f1);
|
mem::release(f->altPresetIdxA);
|
||||||
|
//mem::release(f->multiPresetA);
|
||||||
return kOkRC;
|
mem::release(f);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f0 = f1;
|
rc = cwLogError(kEleNotFoundRC,"The fragment with id %i was not found.",fragId);
|
||||||
}
|
|
||||||
|
|
||||||
return kOkRC;
|
errLabel:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _destroy_all_frags( preset_sel_t* p )
|
void _destroy_all_frags( preset_sel_t* p )
|
||||||
@ -245,7 +261,7 @@ namespace cw
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned alt_strN = textLength(alt_str);
|
unsigned alt_strN = textLength(alt_str);
|
||||||
char alt_str_buf[ alt_strN+1 ] = {0};
|
char alt_str_buf[ alt_strN+1 ];
|
||||||
unsigned asi = 0;
|
unsigned asi = 0;
|
||||||
|
|
||||||
// clear the alt's pointing to the selected preset - because the 'alt_str' has changed
|
// clear the alt's pointing to the selected preset - because the 'alt_str' has changed
|
||||||
@ -261,6 +277,9 @@ namespace cw
|
|||||||
alt_str_buf[ asi++ ] = alt_str[i];
|
alt_str_buf[ asi++ ] = alt_str[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( asi <= alt_strN );
|
||||||
|
alt_str_buf[asi] = 0;
|
||||||
|
|
||||||
// store the preset's new alt str.
|
// store the preset's new alt str.
|
||||||
f->presetA[ sel_preset_idx ].alt_str = mem::reallocStr(f->presetA[ sel_preset_idx ].alt_str, alt_str_buf);
|
f->presetA[ sel_preset_idx ].alt_str = mem::reallocStr(f->presetA[ sel_preset_idx ].alt_str, alt_str_buf);
|
||||||
}
|
}
|
||||||
@ -1209,33 +1228,7 @@ cw::rc_t cw::preset_sel::create_fragment( handle_t h, unsigned end_loc, time::sp
|
|||||||
cw::rc_t cw::preset_sel::delete_fragment( handle_t h, unsigned fragId )
|
cw::rc_t cw::preset_sel::delete_fragment( handle_t h, unsigned fragId )
|
||||||
{
|
{
|
||||||
preset_sel_t* p = _handleToPtr(h);
|
preset_sel_t* p = _handleToPtr(h);
|
||||||
frag_t* f = p->fragL;
|
return _delete_fragment(p,fragId);
|
||||||
|
|
||||||
for(; f!=nullptr; f=f->link)
|
|
||||||
if( f->fragId == fragId )
|
|
||||||
{
|
|
||||||
if( f->prev == nullptr )
|
|
||||||
p->fragL = f->link;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the previous fragment's end-loc become the
|
|
||||||
// endloc of the deleted fragment
|
|
||||||
f->prev->endLoc = f->endLoc;
|
|
||||||
f->prev->link = f->link;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( f->link != nullptr )
|
|
||||||
f->link->prev = f->prev;
|
|
||||||
|
|
||||||
// release the fragment
|
|
||||||
mem::release(f->presetA);
|
|
||||||
//mem::release(f->multiPresetA);
|
|
||||||
mem::release(f);
|
|
||||||
|
|
||||||
return kOkRC;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cwLogError(kInvalidArgRC,"The fragment '%i' could not be found to delete.",fragId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cw::preset_sel::is_fragment_end_loc( handle_t h, unsigned loc )
|
bool cw::preset_sel::is_fragment_end_loc( handle_t h, unsigned loc )
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwFile.h"
|
#include "cwFile.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -830,7 +830,7 @@ unsigned cw::sfscore::opcode_label_to_id( const char* label )
|
|||||||
const char* cw::sfscore::opcode_id_to_label( unsigned opcode_id )
|
const char* cw::sfscore::opcode_id_to_label( unsigned opcode_id )
|
||||||
{
|
{
|
||||||
const char* label;
|
const char* label;
|
||||||
if((label = idToLabel( _opcodeMapA, opcode_id, kInvalidEvtScId)) == nullptr )
|
if((label = idToLabelNull( _opcodeMapA, opcode_id, kInvalidEvtScId)) == nullptr )
|
||||||
cwLogError(kInvalidArgRC,"The event opcode type id '%i' is not valid.",opcode_id);
|
cwLogError(kInvalidArgRC,"The event opcode type id '%i' is not valid.",opcode_id);
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwObject.h"
|
#include "cwObject.h"
|
||||||
#include "cwText.h"
|
#include "cwText.h"
|
||||||
|
540
cwTest.cpp
Normal file
540
cwTest.cpp
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwText.h"
|
||||||
|
#include "cwNumericConvert.h"
|
||||||
|
#include "cwObject.h"
|
||||||
|
#include "cwLex.h"
|
||||||
|
|
||||||
|
#include "cwTime.h"
|
||||||
|
#include "cwFile.h"
|
||||||
|
#include "cwFileSys.h"
|
||||||
|
#include "cwVectOps.h"
|
||||||
|
#include "cwFlowTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
typedef struct test_map_str
|
||||||
|
{
|
||||||
|
const char* module_name;
|
||||||
|
test_func_t test_func;
|
||||||
|
} test_map_t;
|
||||||
|
|
||||||
|
test_map_t _test_map[] = {
|
||||||
|
{ "/lex", lex::test },
|
||||||
|
{ "/filesys", filesys::test },
|
||||||
|
{ "/object", object_test },
|
||||||
|
{ "/vop", vop::test },
|
||||||
|
{ "/time", time::test },
|
||||||
|
{ "/flow", flow::test },
|
||||||
|
{ nullptr, nullptr },
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct test_str
|
||||||
|
{
|
||||||
|
int argc; // extra cmd line arguments to be passes to the test cases
|
||||||
|
const char** argv;
|
||||||
|
|
||||||
|
const char* base_dir; // base test dictionary
|
||||||
|
const object_t* test_cfg; // top level test cfg.
|
||||||
|
|
||||||
|
const char* rsrc_folder; // name of the 'rsrc' folder in the base dir
|
||||||
|
const char* out_folder; // name of the output folder in the base dir
|
||||||
|
const char* ref_folder; // name of the test reference folder in the base dir
|
||||||
|
|
||||||
|
const char* sel_module_label; // selected module label
|
||||||
|
const char* sel_test_label; // selected test label
|
||||||
|
bool all_module_fl; // true if all modules should be run
|
||||||
|
bool all_test_fl; // true if all tests in the selected module should be run
|
||||||
|
bool compare_fl; // true if compare operation should be run
|
||||||
|
bool echo_fl; // echo test output to the console (false=write all output to log file only)
|
||||||
|
bool gen_report_fl; // print module/test names as the gen phase is executes
|
||||||
|
|
||||||
|
void* logCbArg; // original log callback args
|
||||||
|
log::logOutputCbFunc_t logCbFunc;
|
||||||
|
|
||||||
|
const char* cur_test_label; // current test label
|
||||||
|
file::handle_t cur_log_fileH; // current log file handle
|
||||||
|
|
||||||
|
unsigned gen_cnt; // count of tests which generated output
|
||||||
|
unsigned compare_ok_cnt; // count of tests which passed the compare pass
|
||||||
|
unsigned compare_fail_cnt; // count of tests which failed the compare test
|
||||||
|
|
||||||
|
} test_t;
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _parse_args( test_t& test, const object_t* cfg, int argc, const char** argv )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned argN = 1;
|
||||||
|
char* out_dir = nullptr;
|
||||||
|
int argi = 1;
|
||||||
|
|
||||||
|
test.all_module_fl = true;
|
||||||
|
test.all_test_fl = true;
|
||||||
|
|
||||||
|
if( argc > 1 )
|
||||||
|
{
|
||||||
|
test.sel_module_label = argv[1];
|
||||||
|
test.all_module_fl = textIsEqual(test.sel_module_label,"all");
|
||||||
|
argi += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( argc > 2 )
|
||||||
|
{
|
||||||
|
test.sel_test_label = argv[2];
|
||||||
|
test.all_test_fl = textIsEqual(test.sel_test_label,"all");
|
||||||
|
argi += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=argi; i<argc; ++i)
|
||||||
|
{
|
||||||
|
if( textIsEqual(argv[i],"compare") )
|
||||||
|
test.compare_fl = true;
|
||||||
|
|
||||||
|
if( textIsEqual(argv[i],"echo") )
|
||||||
|
test.echo_fl = true;
|
||||||
|
|
||||||
|
if( textIsEqual(argv[i],"gen_report"))
|
||||||
|
test.gen_report_fl = true;
|
||||||
|
|
||||||
|
// test specific args follow the 'args' keyword
|
||||||
|
if( textIsEqual(argv[i],"args") )
|
||||||
|
{
|
||||||
|
test.argc = argc - (i+1);
|
||||||
|
test.argv = argv + (i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = cfg->readv("base_dir",0,test.base_dir,
|
||||||
|
"test",kDictTId,test.test_cfg,
|
||||||
|
"resource_dir",0,test.rsrc_folder,
|
||||||
|
"output_dir",0,test.out_folder,
|
||||||
|
"ref_dir",0,test.ref_folder)) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((out_dir = filesys::makeFn(test.base_dir, nullptr, nullptr, test.out_folder, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Output directory name formation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !filesys::isDir(out_dir))
|
||||||
|
{
|
||||||
|
if((rc = filesys::makeDir(out_dir)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(out_dir);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _exec_test_log_cb( void* cbArg, unsigned level, const char* text )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
test_t* r = (test_t*)cbArg;
|
||||||
|
|
||||||
|
if((rc = file::print(r->cur_log_fileH,text)) != kOkRC )
|
||||||
|
cwLogError(rc,"Log file write failed for '%s'.",text);
|
||||||
|
|
||||||
|
if( r->logCbFunc != nullptr && r->echo_fl )
|
||||||
|
r->logCbFunc( r->logCbArg,level,text);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _exec_dispatch( test_t& test, test_args_t& args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
// find the requested test function ....
|
||||||
|
for(; _test_map[i].module_name!=nullptr; ++i)
|
||||||
|
if( textIsEqual(_test_map[i].module_name,args.module_label) )
|
||||||
|
{
|
||||||
|
rc = _test_map[i].test_func(args); //.... and call it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _test_map[i].module_name==nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kEleNotFoundRC,"The test function for module %s was not found.",cwStringNullGuard(args.module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _compare_one_test( test_t& test, const char* ref_dir, const char* test_dir )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned testRefDirN = 0;
|
||||||
|
filesys::dirEntry_t* testRefDirA = nullptr;
|
||||||
|
bool ok_fl = true;
|
||||||
|
|
||||||
|
// get the list of files in the test directory
|
||||||
|
if((testRefDirA = filesys::dirEntries( ref_dir, filesys::kFileFsFl, &testRefDirN )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"An error occurred while attempting to read the directory file names from '%s'.",cwStringNullGuard(ref_dir));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each file
|
||||||
|
for(unsigned j=0; rc==kOkRC && j<testRefDirN; ++j)
|
||||||
|
if( testRefDirA[j].name != nullptr )
|
||||||
|
{
|
||||||
|
char* testRefFn = filesys::makeFn( ref_dir, testRefDirA[j].name, nullptr, nullptr );
|
||||||
|
char* testCmpFn = filesys::makeFn( test_dir, testRefDirA[j].name, nullptr, nullptr );
|
||||||
|
bool isEqualFl = false;
|
||||||
|
|
||||||
|
// compare two files
|
||||||
|
if((rc = file::compare( testRefFn, testCmpFn, isEqualFl)) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"The comparison failed on '%s' == '%s'.",cwStringNullGuard(testRefFn),cwStringNullGuard(testCmpFn));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check compare status
|
||||||
|
if( !isEqualFl )
|
||||||
|
{
|
||||||
|
ok_fl = false;
|
||||||
|
cwLogInfo("Test failed on: '%s'",testRefFn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::release(testRefFn);
|
||||||
|
mem::release(testCmpFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::release(testRefDirA);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
if( ok_fl )
|
||||||
|
test.compare_ok_cnt += 1;
|
||||||
|
else
|
||||||
|
test.compare_fail_cnt += 1;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _exec_one_test( test_t& test, const char* module_label, const object_t* module_args, const char* test_label, const object_t* test_args )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* rsrc_dir = nullptr;
|
||||||
|
char* out_dir = nullptr;
|
||||||
|
char* ref_dir = nullptr;
|
||||||
|
char* log_fname = nullptr;
|
||||||
|
test_args_t args = {};
|
||||||
|
|
||||||
|
|
||||||
|
if((rsrc_dir = filesys::makeFn( test.base_dir, nullptr, nullptr, test.rsrc_folder, module_label, test_label, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Resource directory '%s' formation failed.",cwStringNullGuard(rsrc_dir));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((out_dir = filesys::makeFn( test.base_dir, nullptr, nullptr, test.out_folder, module_label, test_label, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Output directory '%s' formation failed.",cwStringNullGuard(out_dir));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ref_dir = filesys::makeFn( test.base_dir, nullptr, nullptr, test.ref_folder, module_label, test_label, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Reference directory '%s' formation failed.",cwStringNullGuard(ref_dir));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((log_fname = filesys::makeFn( out_dir, "log","txt",nullptr,nullptr)) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Log filename '%s' formation failed.",cwStringNullGuard(log_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !filesys::isDir(out_dir))
|
||||||
|
{
|
||||||
|
if((rc = filesys::makeDir(out_dir)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Output directory '%s' create failed.",cwStringNullGuard(out_dir));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the log file
|
||||||
|
if((rc = file::open(test.cur_log_fileH, log_fname,file::kWriteFl)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The log file '%s' could not be created.",cwStringNullGuard(log_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( test.gen_report_fl )
|
||||||
|
cwLogInfo("%s %s",module_label,test_label);
|
||||||
|
|
||||||
|
// save the log to a
|
||||||
|
test.logCbArg = log::outputCbArg( log::globalHandle() );
|
||||||
|
test.logCbFunc = log::outputCb( log::globalHandle() );
|
||||||
|
|
||||||
|
log::setOutputCb( log::globalHandle(), _exec_test_log_cb, &test );
|
||||||
|
|
||||||
|
|
||||||
|
args.module_label = module_label;
|
||||||
|
args.test_label = test_label;
|
||||||
|
args.module_args = module_args;
|
||||||
|
args.test_args = test_args;
|
||||||
|
args.rsrc_dir = rsrc_dir;
|
||||||
|
args.out_dir = out_dir;
|
||||||
|
args.argc = test.argc;
|
||||||
|
args.argv = test.argv;
|
||||||
|
|
||||||
|
if((rc = _exec_dispatch(test, args )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
test.gen_cnt += 1;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
file::close(test.cur_log_fileH);
|
||||||
|
log::setOutputCb( log::globalHandle(), test.logCbFunc, test.logCbArg );
|
||||||
|
|
||||||
|
// if compare is enabled
|
||||||
|
if( rc == kOkRC && test.compare_fl )
|
||||||
|
rc = _compare_one_test(test, ref_dir, out_dir );
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Test process failed on module:%s test:%s.",module_label,test_label);
|
||||||
|
|
||||||
|
mem::release(log_fname);
|
||||||
|
mem::release(rsrc_dir);
|
||||||
|
mem::release(out_dir);
|
||||||
|
mem::release(ref_dir);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _exec_cases( test_t& test, const char* module_label, const object_t* module_args, const object_t* cases_cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// get count of test cases
|
||||||
|
unsigned testN = cases_cfg->child_count();
|
||||||
|
|
||||||
|
// for each test case
|
||||||
|
for(unsigned i=0; i<testN; ++i)
|
||||||
|
{
|
||||||
|
const object_t* test_pair = cases_cfg->child_ele(i);
|
||||||
|
const char* test_label = test_pair->pair_label();
|
||||||
|
|
||||||
|
// apply filter/test label filter
|
||||||
|
if( (test.all_module_fl || textIsEqual(module_label,test.sel_module_label)) &&
|
||||||
|
( test.all_test_fl || textIsEqual(test_label,test.sel_test_label)))
|
||||||
|
{
|
||||||
|
if((rc = _exec_one_test(test, module_label, module_args, test_label, test_pair->pair_value() )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _exec_module( test_t& test, const char* module_label, const object_t* module_args, const object_t* module_cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
const object_t* cases_cfg = nullptr;
|
||||||
|
const object_t* mod_args_cfg = nullptr;
|
||||||
|
|
||||||
|
if((rc = module_cfg->getv_opt("cases",cases_cfg,
|
||||||
|
"module_args",mod_args_cfg)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Parse failed on module fields in '%s'.",cwStringNullGuard(module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( cases_cfg == nullptr )
|
||||||
|
cases_cfg = module_cfg;
|
||||||
|
|
||||||
|
if( mod_args_cfg == nullptr )
|
||||||
|
mod_args_cfg = module_args;
|
||||||
|
|
||||||
|
if((rc = _exec_cases( test,module_label,mod_args_cfg,cases_cfg)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _proc_test_cfg( test_t& test, const char* module_label, const object_t* test_cfg );
|
||||||
|
|
||||||
|
rc_t _proc_test_from_file( test_t& test, const char* module_label, const char* fname )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* cfg_fname;
|
||||||
|
object_t* test_cases_cfg = nullptr;
|
||||||
|
const char* orig_base_dir = test.base_dir;
|
||||||
|
char* new_base_dir = nullptr;
|
||||||
|
|
||||||
|
if((cfg_fname = filesys::makeFn(test.base_dir, fname, nullptr, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"The test cases file name for the module '%s' in '%s' / '%s' could not be formed.",cwStringNullGuard(module_label),cwStringNullGuard(test.base_dir),cwStringNullGuard(fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = objectFromFile( cfg_fname, test_cases_cfg )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Parse failed on the test case module file '%s'.",cwStringNullGuard(cfg_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((new_base_dir = filesys::makeFn(test.base_dir, nullptr, nullptr, test.out_folder, module_label, nullptr )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"The base test directory name for the module '%s' could not be formed in '%s'.",cwStringNullGuard(test.base_dir),cwStringNullGuard(module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !filesys::isDir(new_base_dir))
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"The base test directory '%s' for the module '%s' does not exist.",cwStringNullGuard(test.base_dir),cwStringNullGuard(module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _proc_test_cfg( test, module_label, test_cases_cfg );
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(cfg_fname);
|
||||||
|
mem::release(new_base_dir);
|
||||||
|
|
||||||
|
if( test_cases_cfg != nullptr )
|
||||||
|
test_cases_cfg->free();
|
||||||
|
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _proc_module( test_t& test, const char* base_module_label, const char* module_label, const object_t* module_cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* new_module_label = filesys::makeFn(base_module_label,nullptr,nullptr,module_label,nullptr );
|
||||||
|
|
||||||
|
switch( module_cfg->type_id() )
|
||||||
|
{
|
||||||
|
case kStringTId:
|
||||||
|
{
|
||||||
|
const char* s = nullptr;
|
||||||
|
if((rc = module_cfg->value(s)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Parse failed on module filename in '%s'.",cwStringNullGuard(module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _proc_test_from_file(test, new_module_label, s );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDictTId:
|
||||||
|
rc = _proc_test_cfg(test, new_module_label, module_cfg );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(new_module_label);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _proc_test_cfg( test_t& test, const char* module_label, const object_t* test_cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const object_t* module_args = nullptr;
|
||||||
|
const object_t* modules_cfg = nullptr;
|
||||||
|
const object_t* cases_cfg = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = test_cfg->getv_opt("module_args",module_args,
|
||||||
|
"modules",modules_cfg,
|
||||||
|
"cases",cases_cfg )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The 'module_args' parse failed on module '%s'.",cwStringNullGuard(module_label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a list of modules was given
|
||||||
|
if( modules_cfg != nullptr )
|
||||||
|
{
|
||||||
|
unsigned modulesN = modules_cfg->child_count();
|
||||||
|
for(unsigned i=0; i<modulesN; ++i)
|
||||||
|
{
|
||||||
|
const object_t* mod_pair = modules_cfg->child_ele(i);
|
||||||
|
|
||||||
|
if((rc = _proc_module(test, module_label, mod_pair->pair_label(), mod_pair->pair_value() )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if
|
||||||
|
if(module_args==nullptr && modules_cfg==nullptr && cases_cfg==nullptr )
|
||||||
|
{
|
||||||
|
cases_cfg = test_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a list of cases was given
|
||||||
|
if( cases_cfg != nullptr )
|
||||||
|
{
|
||||||
|
if((rc = _exec_cases(test,module_label,module_args,cases_cfg)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::test::test( const struct object_str* cfg, int argc, const char** argv )
|
||||||
|
{
|
||||||
|
test_t test = {};
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if((rc = _parse_args(test, cfg, argc, argv )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Test arguments parse failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = _proc_test_cfg(test,"/",test.test_cfg)) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
cwLogInfo("Test Gen Count:%i.",test.gen_cnt);
|
||||||
|
|
||||||
|
if( test.compare_fl )
|
||||||
|
cwLogInfo("Test Compare - ok:%i fail:%i.",test.compare_ok_cnt,test.compare_fail_cnt);
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Testing process failed.");
|
||||||
|
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
31
cwTest.h
Normal file
31
cwTest.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef cwTest_h
|
||||||
|
#define cwTest_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
struct object_str;
|
||||||
|
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef struct test_args_str
|
||||||
|
{
|
||||||
|
const char* module_label; // test module this test belongs to
|
||||||
|
const char* test_label; // test label
|
||||||
|
const struct object_str* module_args; // arguments for all tests in this module
|
||||||
|
const struct object_str* test_args; // arguments specific to this test
|
||||||
|
const char* rsrc_dir; // input data dir. for this test
|
||||||
|
const char* out_dir; // output data dir. for this test
|
||||||
|
int argc; // cmd line arg count
|
||||||
|
const char** argv; // cmd line arg's
|
||||||
|
|
||||||
|
} test_args_t;
|
||||||
|
|
||||||
|
typedef rc_t (*test_func_t)(const test_args_t& args);
|
||||||
|
|
||||||
|
rc_t test( const struct object_str* cfg, int argc, const char** argv );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
16
cwText.cpp
16
cwText.cpp
@ -146,7 +146,7 @@ const char* cw::nextNonWhiteChar( const char* s )
|
|||||||
const char* cw::nextNonWhiteCharEOS( const char* s )
|
const char* cw::nextNonWhiteCharEOS( const char* s )
|
||||||
{ return _nextNonWhiteChar(s,true); }
|
{ return _nextNonWhiteChar(s,true); }
|
||||||
|
|
||||||
const char* cw::firstMatchChar( const char* s, char c )
|
char* cw::firstMatchChar( char* s, char c )
|
||||||
{
|
{
|
||||||
if( s == nullptr )
|
if( s == nullptr )
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -157,7 +157,12 @@ const char* cw::firstMatchChar( const char* s, char c )
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cw::lastMatchChar( const char* s, char c )
|
const char* cw::firstMatchChar( const char* s, char c )
|
||||||
|
{
|
||||||
|
return firstMatchChar((char*)s,c);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* cw::lastMatchChar( char* s, char c )
|
||||||
{
|
{
|
||||||
unsigned sn;
|
unsigned sn;
|
||||||
|
|
||||||
@ -168,13 +173,18 @@ const char* cw::lastMatchChar( const char* s, char c )
|
|||||||
if( sn == 0 )
|
if( sn == 0 )
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
for(const char* s1=s+(sn-1); s<=s1; --s1)
|
for(char* s1=s+(sn-1); s<=s1; --s1)
|
||||||
if( *s1 == c )
|
if( *s1 == c )
|
||||||
return s1;
|
return s1;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* cw::lastMatchChar( const char* s, char c )
|
||||||
|
{
|
||||||
|
return lastMatchChar((char*)s,c);
|
||||||
|
}
|
||||||
|
|
||||||
bool cw::isInteger( const char* s )
|
bool cw::isInteger( const char* s )
|
||||||
{
|
{
|
||||||
for(; *s; ++s)
|
for(; *s; ++s)
|
||||||
|
5
cwText.h
5
cwText.h
@ -8,7 +8,7 @@ namespace cw
|
|||||||
unsigned textLength( const char* s );
|
unsigned textLength( const char* s );
|
||||||
|
|
||||||
// If dst is non-null then dst is always 0-terminated.
|
// If dst is non-null then dst is always 0-terminated.
|
||||||
// If src will be truncated if srcN > dstN-1.
|
// src will be truncated if srcN > dstN-1.
|
||||||
// If dst is null then null is returned
|
// If dst is null then null is returned
|
||||||
// if src is null then dst[0] = 0.
|
// if src is null then dst[0] = 0.
|
||||||
// if srcN is 0 then textLength(src) is used for srcN
|
// if srcN is 0 then textLength(src) is used for srcN
|
||||||
@ -65,8 +65,11 @@ namespace cw
|
|||||||
|
|
||||||
// Return a pointer to the first occurrence of 'c' in s[] or nullptr
|
// Return a pointer to the first occurrence of 'c' in s[] or nullptr
|
||||||
// if 'c' does not occur in s[]
|
// if 'c' does not occur in s[]
|
||||||
|
char* firstMatchChar( char* s, char c );
|
||||||
const char* firstMatchChar( const char* s, char c );
|
const char* firstMatchChar( const char* s, char c );
|
||||||
|
|
||||||
// Find the last occurrent of 'c' in s[].
|
// Find the last occurrent of 'c' in s[].
|
||||||
|
char* lastMatchChar( char* s, char c );
|
||||||
const char* lastMatchChar( const char* s, char c );
|
const char* lastMatchChar( const char* s, char c );
|
||||||
|
|
||||||
bool isInteger( const char* ); // text contains only [0-9]
|
bool isInteger( const char* ); // text contains only [0-9]
|
||||||
|
15
cwTime.cpp
15
cwTime.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
|
|
||||||
#ifdef OS_OSX
|
#ifdef OS_OSX
|
||||||
@ -399,7 +400,7 @@ unsigned cw::time::formatDateTime( char* buffer, unsigned bufN, bool includeDate
|
|||||||
return (unsigned)n;
|
return (unsigned)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::time::test()
|
cw::rc_t cw::time::test(const test::test_args_t& test )
|
||||||
{
|
{
|
||||||
|
|
||||||
spec_t t0,t1;
|
spec_t t0,t1;
|
||||||
@ -410,15 +411,15 @@ cw::rc_t cw::time::test()
|
|||||||
|
|
||||||
unsigned dMs = elapsedMs(t0,t1);
|
unsigned dMs = elapsedMs(t0,t1);
|
||||||
|
|
||||||
printf("dMs:%i : GTE:%i LTE:%i\n",dMs, isGTE(t0,t1), isLTE(t0,t1) );
|
cwLogPrint("dMs:%i : GTE:%i LTE:%i\n",dMs, isGTE(t0,t1), isLTE(t0,t1) );
|
||||||
|
|
||||||
|
|
||||||
microsecondsToSpec( t0, 2500000 ); // 2.5 seconds
|
microsecondsToSpec( t0, 2500000 ); // 2.5 seconds
|
||||||
printf("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
cwLogPrint("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
||||||
subtractMicros( t0, 750000 ); // subtract .75 seconds
|
subtractMicros( t0, 750000 ); // subtract .75 seconds
|
||||||
printf("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
cwLogPrint("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
||||||
subtractMicros( t0, 500000 ); // subtract .5 seconds
|
subtractMicros( t0, 500000 ); // subtract .5 seconds
|
||||||
printf("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
cwLogPrint("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
||||||
|
|
||||||
|
|
||||||
time::get(t0);
|
time::get(t0);
|
||||||
@ -429,11 +430,11 @@ cw::rc_t cw::time::test()
|
|||||||
|
|
||||||
int usec = time::elapsedMicros(t0,t1);
|
int usec = time::elapsedMicros(t0,t1);
|
||||||
|
|
||||||
printf("usec:%i\n",usec);
|
cwLogPrint("usec:%i\n",usec);
|
||||||
|
|
||||||
t0 = current_time();
|
t0 = current_time();
|
||||||
sleepMs(1000);
|
sleepMs(1000);
|
||||||
printf("sleep %i ms\n",elapsedMs(t0));
|
cwLogPrint("sleep %i ms\n",elapsedMs(t0));
|
||||||
|
|
||||||
|
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
|
2
cwTime.h
2
cwTime.h
@ -85,7 +85,7 @@ namespace cw
|
|||||||
// Return count of bytes in in buf[]
|
// Return count of bytes in in buf[]
|
||||||
unsigned formatDateTime( char* buf, unsigned bufN, bool includeDateFl=false );
|
unsigned formatDateTime( char* buf, unsigned bufN, bool includeDateFl=false );
|
||||||
|
|
||||||
rc_t test();
|
rc_t test( const test::test_args_t& test );
|
||||||
|
|
||||||
//)
|
//)
|
||||||
|
|
||||||
|
128
cwUi.cpp
128
cwUi.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwTime.h"
|
#include "cwTime.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
@ -117,7 +118,7 @@ namespace cw
|
|||||||
unsigned sentMsgN;
|
unsigned sentMsgN;
|
||||||
unsigned recvMsgN;
|
unsigned recvMsgN;
|
||||||
|
|
||||||
bucket_t hashA[ hashN ];
|
bucket_t hashA[ hashN+1 ];
|
||||||
|
|
||||||
} ui_t;
|
} ui_t;
|
||||||
|
|
||||||
@ -129,7 +130,11 @@ namespace cw
|
|||||||
assert( parentUuId != kInvalidId && appId != kInvalidId );
|
assert( parentUuId != kInvalidId && appId != kInvalidId );
|
||||||
unsigned hc = parentUuId + cwSwap32(appId);
|
unsigned hc = parentUuId + cwSwap32(appId);
|
||||||
|
|
||||||
return (unsigned short)(((hc & 0xffff0000)>>16) + (hc & 0x0000ffff));
|
unsigned short hash_idx = (unsigned short)(((hc & 0xffff0000)>>16) + (hc & 0x0000ffff));
|
||||||
|
|
||||||
|
assert( hash_idx <= hashN );
|
||||||
|
|
||||||
|
return hash_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -162,7 +167,7 @@ namespace cw
|
|||||||
bucket_t* b = p->hashA + hash_idx;
|
bucket_t* b = p->hashA + hash_idx;
|
||||||
|
|
||||||
for(; b!=nullptr; b=b->link)
|
for(; b!=nullptr; b=b->link)
|
||||||
if( b->ele->appId==appId && b->ele->logical_parent->uuId==parentUuId && (chanId==kInvalidId || b->ele->chanId==chanId) )
|
if( b->ele != nullptr && b->ele->logical_parent!=nullptr && b->ele->appId==appId && b->ele->logical_parent->uuId==parentUuId && (chanId==kInvalidId || b->ele->chanId==chanId) )
|
||||||
return b->ele->uuId;
|
return b->ele->uuId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +230,18 @@ namespace cw
|
|||||||
m = m0;
|
m = m0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: hashA[] has hashN+1 elements
|
||||||
|
for(unsigned i=0; i<=hashN; ++i)
|
||||||
|
{
|
||||||
|
bucket_t* b = p->hashA[i].link;
|
||||||
|
while( b!=nullptr )
|
||||||
|
{
|
||||||
|
bucket_t* b0 = b->link;
|
||||||
|
mem::release(b);
|
||||||
|
b = b0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mem::release(p->sessA);
|
mem::release(p->sessA);
|
||||||
mem::release(p->eleA);
|
mem::release(p->eleA);
|
||||||
mem::release(p->buf);
|
mem::release(p->buf);
|
||||||
@ -2219,6 +2236,7 @@ void cw::ui::realTimeReport( handle_t h )
|
|||||||
{
|
{
|
||||||
ui_t* p = _handleToPtr(h);
|
ui_t* p = _handleToPtr(h);
|
||||||
printf("UI msg count: recv:%i send:%i\n",p->recvMsgN,p->sentMsgN);
|
printf("UI msg count: recv:%i send:%i\n",p->recvMsgN,p->sentMsgN);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2235,7 +2253,6 @@ namespace cw
|
|||||||
void* cbArg;
|
void* cbArg;
|
||||||
uiCallback_t uiCbFunc;
|
uiCallback_t uiCbFunc;
|
||||||
websock::cbFunc_t wsCbFunc;
|
websock::cbFunc_t wsCbFunc;
|
||||||
unsigned wsTimeOutMs;
|
|
||||||
unsigned idleMsgPeriodMs;
|
unsigned idleMsgPeriodMs;
|
||||||
time::spec_t lastRecvMsgTimeStamp;
|
time::spec_t lastRecvMsgTimeStamp;
|
||||||
} ui_ws_t;
|
} ui_ws_t;
|
||||||
@ -2317,13 +2334,18 @@ cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* ob
|
|||||||
"rcvBufByteN", args.rcvBufByteN,
|
"rcvBufByteN", args.rcvBufByteN,
|
||||||
"xmtBufByteN", args.xmtBufByteN,
|
"xmtBufByteN", args.xmtBufByteN,
|
||||||
"fmtBufByteN", args.fmtBufByteN,
|
"fmtBufByteN", args.fmtBufByteN,
|
||||||
"websockTimeOutMs", args.wsTimeOutMs,
|
|
||||||
"idleMsgPeriodMs", args.idleMsgPeriodMs,
|
"idleMsgPeriodMs", args.idleMsgPeriodMs,
|
||||||
|
"queueBlkCnt", args.queueBlkCnt,
|
||||||
|
"queueBlkByteCnt", args.queueBlkByteCnt,
|
||||||
"uiCfgFn", uiCfgFn )) != kOkRC )
|
"uiCfgFn", uiCfgFn )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"'ui' cfg. parse failed.");
|
rc = cwLogError(rc,"'ui' cfg. parse failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( op->find_child("websockTimeOutMs") != nullptr )
|
||||||
|
cwLogWarning("The UI parameter 'websockTimeOutMs' is obsolete and ignored.");
|
||||||
|
|
||||||
|
|
||||||
// expand the physical root directory
|
// expand the physical root directory
|
||||||
if((physRootDir = filesys::expandPath( args.physRootDir)) == nullptr )
|
if((physRootDir = filesys::expandPath( args.physRootDir)) == nullptr )
|
||||||
{
|
{
|
||||||
@ -2374,11 +2396,12 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
|||||||
appIdMapN,
|
appIdMapN,
|
||||||
wsCbFunc,
|
wsCbFunc,
|
||||||
args.dfltPageFn,
|
args.dfltPageFn,
|
||||||
args.wsTimeOutMs,
|
|
||||||
args.idleMsgPeriodMs,
|
args.idleMsgPeriodMs,
|
||||||
args.rcvBufByteN,
|
args.rcvBufByteN,
|
||||||
args.xmtBufByteN,
|
args.xmtBufByteN,
|
||||||
args.fmtBufByteN );
|
args.fmtBufByteN,
|
||||||
|
args.queueBlkCnt,
|
||||||
|
args.queueBlkByteCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2392,11 +2415,12 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
|||||||
unsigned appIdMapN,
|
unsigned appIdMapN,
|
||||||
websock::cbFunc_t wsCbFunc,
|
websock::cbFunc_t wsCbFunc,
|
||||||
const char* dfltPageFn,
|
const char* dfltPageFn,
|
||||||
unsigned websockTimeOutMs,
|
|
||||||
unsigned idleMsgPeriodMs,
|
unsigned idleMsgPeriodMs,
|
||||||
unsigned rcvBufByteN,
|
unsigned rcvBufByteN,
|
||||||
unsigned xmtBufByteN,
|
unsigned xmtBufByteN,
|
||||||
unsigned fmtBufByteN )
|
unsigned fmtBufByteN,
|
||||||
|
unsigned queueBlkCnt,
|
||||||
|
unsigned queueBlkByteCnt )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
@ -2416,7 +2440,7 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
|||||||
void* wsCbA = wsCbFunc==nullptr ? p : cbArg;
|
void* wsCbA = wsCbFunc==nullptr ? p : cbArg;
|
||||||
|
|
||||||
// create the websocket
|
// create the websocket
|
||||||
if((rc = websock::create(p->wsH, wsCbF, wsCbA, physRootDir, dfltPageFn, port, protocolA, protocolN )) != kOkRC )
|
if((rc = websock::create(p->wsH, wsCbF, wsCbA, physRootDir, dfltPageFn, port, protocolA, protocolN, queueBlkCnt, queueBlkByteCnt )) != kOkRC )
|
||||||
{
|
{
|
||||||
cwLogError(rc,"UI Websock create failed.");
|
cwLogError(rc,"UI Websock create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -2432,7 +2456,6 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
|||||||
p->cbArg = cbArg;
|
p->cbArg = cbArg;
|
||||||
p->uiCbFunc = uiCbFunc;
|
p->uiCbFunc = uiCbFunc;
|
||||||
p->wsCbFunc = wsCbFunc;
|
p->wsCbFunc = wsCbFunc;
|
||||||
p->wsTimeOutMs = websockTimeOutMs;
|
|
||||||
p->idleMsgPeriodMs = idleMsgPeriodMs;
|
p->idleMsgPeriodMs = idleMsgPeriodMs;
|
||||||
// initialize the last received msg
|
// initialize the last received msg
|
||||||
time::get(p->lastRecvMsgTimeStamp);
|
time::get(p->lastRecvMsgTimeStamp);
|
||||||
@ -2465,13 +2488,13 @@ cw::rc_t cw::ui::ws::destroy( handle_t& h )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::ui::ws::exec( handle_t h )
|
cw::rc_t cw::ui::ws::exec( handle_t h, unsigned wsTimeOutMs )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
|
||||||
ui_ws_t* p = _handleToPtr(h);
|
ui_ws_t* p = _handleToPtr(h);
|
||||||
|
rc_t rc = kOkRC;
|
||||||
time::spec_t t;
|
time::spec_t t;
|
||||||
|
|
||||||
if((rc = websock::exec( p->wsH, p->wsTimeOutMs )) != kOkRC)
|
if((rc = websock::exec( p->wsH, wsTimeOutMs )) != kOkRC)
|
||||||
cwLogError(rc,"The UI websock execution failed.");
|
cwLogError(rc,"The UI websock execution failed.");
|
||||||
|
|
||||||
// make the idle callback
|
// make the idle callback
|
||||||
@ -2486,6 +2509,7 @@ cw::rc_t cw::ui::ws::exec( handle_t h )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::ui::ws::onReceive( handle_t h, unsigned protocolId, unsigned sessionId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
|
cw::rc_t cw::ui::ws::onReceive( handle_t h, unsigned protocolId, unsigned sessionId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
|
||||||
{
|
{
|
||||||
ui_ws_t* p = _handleToPtr(h);
|
ui_ws_t* p = _handleToPtr(h);
|
||||||
@ -2508,6 +2532,13 @@ cw::ui::handle_t cw::ui::ws::uiHandle( handle_t h )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cw::ui::ws::realTimeReport( handle_t h )
|
||||||
|
{
|
||||||
|
ui_ws_t* p = _handleToPtr(h);
|
||||||
|
report(p->wsH);
|
||||||
|
realTimeReport(p->uiH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace cw
|
namespace cw
|
||||||
{
|
{
|
||||||
@ -2519,6 +2550,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
ws::handle_t wsUiH;
|
ws::handle_t wsUiH;
|
||||||
thread::handle_t thH;
|
thread::handle_t thH;
|
||||||
|
unsigned wsTimeOutMs;
|
||||||
} ui_ws_srv_t;
|
} ui_ws_srv_t;
|
||||||
|
|
||||||
ui_ws_srv_t* _handleToPtr(handle_t h )
|
ui_ws_srv_t* _handleToPtr(handle_t h )
|
||||||
@ -2543,7 +2575,7 @@ namespace cw
|
|||||||
ui_ws_srv_t* p = static_cast<ui_ws_srv_t*>(arg);
|
ui_ws_srv_t* p = static_cast<ui_ws_srv_t*>(arg);
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
|
|
||||||
if((rc = ws::exec(p->wsUiH)) != kOkRC )
|
if((rc = ws::exec(p->wsUiH,p->wsTimeOutMs)) != kOkRC )
|
||||||
{
|
{
|
||||||
cwLogError(rc,"Websocket UI exec failed.");
|
cwLogError(rc,"Websocket UI exec failed.");
|
||||||
}
|
}
|
||||||
@ -2554,6 +2586,34 @@ namespace cw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::ui::srv::create( handle_t& h,
|
||||||
|
const ws::args_t& args,
|
||||||
|
void* cbArg,
|
||||||
|
uiCallback_t uiCbFunc,
|
||||||
|
const appIdMap_t* appIdMapA,
|
||||||
|
unsigned appIdMapN,
|
||||||
|
unsigned wsTimeOutMs,
|
||||||
|
websock::cbFunc_t wsCbFunc )
|
||||||
|
{
|
||||||
|
return create(h,
|
||||||
|
args.port,
|
||||||
|
args.physRootDir,
|
||||||
|
cbArg,
|
||||||
|
uiCbFunc,
|
||||||
|
args.uiRsrc,
|
||||||
|
appIdMapA,
|
||||||
|
appIdMapN,
|
||||||
|
wsTimeOutMs,
|
||||||
|
wsCbFunc,
|
||||||
|
args.dfltPageFn,
|
||||||
|
args.idleMsgPeriodMs,
|
||||||
|
args.rcvBufByteN,
|
||||||
|
args.xmtBufByteN,
|
||||||
|
args.fmtBufByteN,
|
||||||
|
args.queueBlkCnt,
|
||||||
|
args.queueBlkByteCnt );
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::ui::srv::create( handle_t& h,
|
cw::rc_t cw::ui::srv::create( handle_t& h,
|
||||||
unsigned port,
|
unsigned port,
|
||||||
const char* physRootDir,
|
const char* physRootDir,
|
||||||
@ -2562,12 +2622,15 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
|||||||
const object_t* uiRsrc,
|
const object_t* uiRsrc,
|
||||||
const appIdMap_t* appIdMapA,
|
const appIdMap_t* appIdMapA,
|
||||||
unsigned appIdMapN,
|
unsigned appIdMapN,
|
||||||
|
unsigned wsTimeOutMs,
|
||||||
websock::cbFunc_t wsCbFunc,
|
websock::cbFunc_t wsCbFunc,
|
||||||
const char* dfltPageFn,
|
const char* dfltPageFn,
|
||||||
unsigned websockTimeOutMs,
|
unsigned idleMsgPeriodMs,
|
||||||
unsigned rcvBufByteN,
|
unsigned rcvBufByteN,
|
||||||
unsigned xmtBufByteN,
|
unsigned xmtBufByteN,
|
||||||
unsigned fmtBufByteN )
|
unsigned fmtBufByteN,
|
||||||
|
unsigned queueBlkCnt,
|
||||||
|
unsigned queueBlkByteCnt )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
if((rc = destroy(h)) != kOkRC )
|
if((rc = destroy(h)) != kOkRC )
|
||||||
@ -2575,7 +2638,7 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
|||||||
|
|
||||||
ui_ws_srv_t* p = mem::allocZ<ui_ws_srv_t>();
|
ui_ws_srv_t* p = mem::allocZ<ui_ws_srv_t>();
|
||||||
|
|
||||||
if((rc = ws::create(p->wsUiH, port, physRootDir, cbArg, uiCbFunc, uiRsrc,appIdMapA, appIdMapN, wsCbFunc, dfltPageFn, websockTimeOutMs, rcvBufByteN, xmtBufByteN, fmtBufByteN )) != kOkRC )
|
if((rc = ws::create(p->wsUiH, port, physRootDir, cbArg, uiCbFunc, uiRsrc,appIdMapA, appIdMapN, wsCbFunc, dfltPageFn, idleMsgPeriodMs, rcvBufByteN, xmtBufByteN, fmtBufByteN, queueBlkCnt, queueBlkByteCnt )) != kOkRC )
|
||||||
{
|
{
|
||||||
cwLogError(rc,"The websock UI creationg failed.");
|
cwLogError(rc,"The websock UI creationg failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -2587,6 +2650,8 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->wsTimeOutMs = wsTimeOutMs;
|
||||||
|
|
||||||
h.set(p);
|
h.set(p);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
@ -2596,32 +2661,6 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::ui::srv::create( handle_t& h,
|
|
||||||
const ws::args_t& args,
|
|
||||||
void* cbArg,
|
|
||||||
uiCallback_t uiCbFunc,
|
|
||||||
const appIdMap_t* appIdMapA,
|
|
||||||
unsigned appIdMapN,
|
|
||||||
websock::cbFunc_t wsCbFunc )
|
|
||||||
{
|
|
||||||
return create(h,
|
|
||||||
args.port,
|
|
||||||
args.physRootDir,
|
|
||||||
cbArg,
|
|
||||||
uiCbFunc,
|
|
||||||
args.uiRsrc,
|
|
||||||
appIdMapA,
|
|
||||||
appIdMapN,
|
|
||||||
wsCbFunc,
|
|
||||||
args.dfltPageFn,
|
|
||||||
args.wsTimeOutMs,
|
|
||||||
args.rcvBufByteN,
|
|
||||||
args.xmtBufByteN,
|
|
||||||
args.fmtBufByteN );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::ui::srv::destroy( handle_t& h )
|
cw::rc_t cw::ui::srv::destroy( handle_t& h )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -2677,3 +2716,4 @@ cw::ui::handle_t cw::ui::srv::uiHandle( handle_t h )
|
|||||||
ui_ws_srv_t* p = _handleToPtr(h);
|
ui_ws_srv_t* p = _handleToPtr(h);
|
||||||
return ws::uiHandle(p->wsUiH);
|
return ws::uiHandle(p->wsUiH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
cwUi.h
23
cwUi.h
@ -192,8 +192,9 @@ namespace cw
|
|||||||
unsigned rcvBufByteN;
|
unsigned rcvBufByteN;
|
||||||
unsigned xmtBufByteN;
|
unsigned xmtBufByteN;
|
||||||
unsigned fmtBufByteN;
|
unsigned fmtBufByteN;
|
||||||
unsigned wsTimeOutMs;
|
|
||||||
unsigned idleMsgPeriodMs; // min period without messages before an idle message is generated
|
unsigned idleMsgPeriodMs; // min period without messages before an idle message is generated
|
||||||
|
unsigned queueBlkCnt;
|
||||||
|
unsigned queueBlkByteCnt;
|
||||||
} args_t;
|
} args_t;
|
||||||
|
|
||||||
rc_t parseArgs( const object_t& o, args_t& args, const char* object_label="ui" );
|
rc_t parseArgs( const object_t& o, args_t& args, const char* object_label="ui" );
|
||||||
@ -218,20 +219,20 @@ namespace cw
|
|||||||
unsigned appIdMapN = 0,
|
unsigned appIdMapN = 0,
|
||||||
websock::cbFunc_t wsCbFunc = nullptr,
|
websock::cbFunc_t wsCbFunc = nullptr,
|
||||||
const char* dfltPageFn = "index.html",
|
const char* dfltPageFn = "index.html",
|
||||||
unsigned websockTimeOutMs = 50,
|
|
||||||
unsigned idleMsgPeriodMs = 50,
|
unsigned idleMsgPeriodMs = 50,
|
||||||
unsigned rcvBufByteN = 1024,
|
unsigned rcvBufByteN = 1024,
|
||||||
unsigned xmtBufByteN = 1024,
|
unsigned xmtBufByteN = 1024,
|
||||||
unsigned fmtBufByteN = 4096
|
unsigned fmtBufByteN = 4096,
|
||||||
);
|
unsigned queueBlkCnt = 4,
|
||||||
|
unsigned queueBlkByteCnt = 4096 );
|
||||||
|
|
||||||
rc_t destroy( handle_t& h );
|
rc_t destroy( handle_t& h );
|
||||||
|
|
||||||
// This function should be called periodically to send and receive
|
// This function should be called periodically to send and receive
|
||||||
// queued messages to and from the websocket.
|
// queued messages to and from the websocket.
|
||||||
// Note that this call may block for up to 'wsTimeOutMs' milliseconds
|
// Note that this call may block for up to 'wsTimeOutMs' milliseconds
|
||||||
// on the websocket handle.
|
// while waiting for incoming websocket messages.
|
||||||
rc_t exec( handle_t h );
|
rc_t exec( handle_t h, unsigned wsTimeOutMs );
|
||||||
|
|
||||||
// This function executes the internal default websock callback function.
|
// This function executes the internal default websock callback function.
|
||||||
// It is useful if the user provides a custom websock callback function
|
// It is useful if the user provides a custom websock callback function
|
||||||
@ -240,6 +241,8 @@ namespace cw
|
|||||||
|
|
||||||
websock::handle_t websockHandle( handle_t h );
|
websock::handle_t websockHandle( handle_t h );
|
||||||
ui::handle_t uiHandle( handle_t h );
|
ui::handle_t uiHandle( handle_t h );
|
||||||
|
void realTimeReport( handle_t h );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace srv
|
namespace srv
|
||||||
@ -253,6 +256,7 @@ namespace cw
|
|||||||
uiCallback_t uiCbFunc,
|
uiCallback_t uiCbFunc,
|
||||||
const appIdMap_t* appIdMapA = nullptr,
|
const appIdMap_t* appIdMapA = nullptr,
|
||||||
unsigned appIdMapN = 0,
|
unsigned appIdMapN = 0,
|
||||||
|
unsigned wsTimeOutMs = 50,
|
||||||
websock::cbFunc_t wsCbFunc = nullptr );
|
websock::cbFunc_t wsCbFunc = nullptr );
|
||||||
|
|
||||||
rc_t create( handle_t& h,
|
rc_t create( handle_t& h,
|
||||||
@ -263,12 +267,15 @@ namespace cw
|
|||||||
const object_t* uiRsrc = nullptr,
|
const object_t* uiRsrc = nullptr,
|
||||||
const appIdMap_t* appIdMapA = nullptr,
|
const appIdMap_t* appIdMapA = nullptr,
|
||||||
unsigned appIdMapN = 0,
|
unsigned appIdMapN = 0,
|
||||||
|
unsigned wsTimeOutMs = 50,
|
||||||
websock::cbFunc_t wsCbFunc = nullptr,
|
websock::cbFunc_t wsCbFunc = nullptr,
|
||||||
const char* dfltPageFn = "index.html",
|
const char* dfltPageFn = "index.html",
|
||||||
unsigned websockTimeOutMs = 50,
|
unsigned idleMsgPeriodMs = 50,
|
||||||
unsigned rcvBufByteN = 1024,
|
unsigned rcvBufByteN = 1024,
|
||||||
unsigned xmtBufByteN = 1024,
|
unsigned xmtBufByteN = 1024,
|
||||||
unsigned fmtBufByteN = 4096 );
|
unsigned fmtBufByteN = 4096,
|
||||||
|
unsigned queueBlkCnt = 4,
|
||||||
|
unsigned queueBlkByteCnt = 4096 );
|
||||||
|
|
||||||
|
|
||||||
rc_t destroy( handle_t& h );
|
rc_t destroy( handle_t& h );
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "cwCommon.h"
|
#include "cwCommon.h"
|
||||||
#include "cwLog.h"
|
#include "cwLog.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
#include "cwThread.h"
|
#include "cwThread.h"
|
||||||
#include "cwWebSock.h"
|
#include "cwWebSock.h"
|
||||||
@ -379,6 +380,7 @@ namespace cw
|
|||||||
cw::rc_t cw::ui::test( const object_t* cfg )
|
cw::rc_t cw::ui::test( const object_t* cfg )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
unsigned wsTimeOutMs = 50;
|
||||||
ui::ws::args_t args = {};
|
ui::ws::args_t args = {};
|
||||||
|
|
||||||
// Application Id's for the resource based UI elements.
|
// Application Id's for the resource based UI elements.
|
||||||
@ -437,7 +439,7 @@ cw::rc_t cw::ui::test( const object_t* cfg )
|
|||||||
//app->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg";
|
//app->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg";
|
||||||
|
|
||||||
// create the UI server
|
// create the UI server
|
||||||
if((rc = srv::create(app->wsUiSrvH, args, app, _uiTestCallback, mapA, mapN, nullptr )) != kOkRC )
|
if((rc = srv::create(app->wsUiSrvH, args, app, _uiTestCallback, mapA, mapN, wsTimeOutMs, nullptr )) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if((rc = uiTestCreateUi( app )) != kOkRC )
|
if((rc = uiTestCreateUi( app )) != kOkRC )
|
||||||
|
15
cwVectOps.cpp
Normal file
15
cwVectOps.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwTest.h"
|
||||||
|
#include "cwVectOps.h"
|
||||||
|
|
||||||
|
cw::rc_t cw::vop::test( const test::test_args_t& args )
|
||||||
|
{
|
||||||
|
int v1[] = { 1,2,1,2,1,2,1,2,1,2 };
|
||||||
|
int v0[ 10 ];
|
||||||
|
|
||||||
|
cw::vop::deinterleave( v0, v1, 5, 2 );
|
||||||
|
cw::vop::print(v0,10,"%i ");
|
||||||
|
return cw::kOkRC;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user