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
12
Makefile.am
12
Makefile.am
@ -4,8 +4,8 @@ libcwSRC =
|
||||
libcwHDR += src/libcw/cwCommon.h src/libcw/cwCommonImpl.h src/libcw/cwMem.h src/libcw/cwLog.h src/libcw/cwUtility.h
|
||||
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
|
||||
libcwSRC += src/libcw/cwString.cpp src/libcw/cwMath.cpp src/libcw/cwMtx.cpp src/libcw/cwVariant.cpp
|
||||
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/cwVectOps.cpp src/libcw/cwMtx.cpp src/libcw/cwVariant.cpp
|
||||
|
||||
libcwHDR += src/libcw/cwB23Tree.h
|
||||
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
|
||||
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
|
||||
libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp
|
||||
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/cwFlowNet.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp src/libcw/cwFlowTest.cpp
|
||||
|
||||
if cwWEBSOCK
|
||||
libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h
|
||||
@ -46,8 +46,8 @@ libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp
|
||||
|
||||
endif
|
||||
|
||||
libcwHDR += src/libcw/cwKeyboard.h
|
||||
libcwSRC += src/libcw/cwKeyboard.cpp
|
||||
libcwHDR += src/libcw/cwKeyboard.h src/libcw/cwTest.h
|
||||
libcwSRC += src/libcw/cwKeyboard.cpp src/libcw/cwTest.cpp
|
||||
|
||||
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
||||
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
|
||||
|
||||
*** Raspberry Pi Build Notes:
|
||||
### Raspberry Pi Build Notes:
|
||||
|
||||
cd sdk
|
||||
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().
|
||||
(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.
|
||||
|
||||
*** Flow Instance Creation:
|
||||
### Flow Instance Creation:
|
||||
|
||||
1. Create all vars from the class description and initially set their
|
||||
value to the default value given in the class. chIdx=kAnyChIdx.
|
||||
0. Parse the 'in' list and create any 'mult' variables whose
|
||||
'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.
|
||||
|
||||
|
||||
2. Apply the preset record from the class description according to the
|
||||
label given in the instance definition.
|
||||
2. Apply the preset records from the class description according to the
|
||||
'presets' list given in the instance definition.
|
||||
|
||||
If the variable values are given as a scalar then the existing
|
||||
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
|
||||
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',
|
||||
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
|
||||
is kept, in channel order, using the 'ch_link' links with the base of the list
|
||||
on the 'any' record.
|
||||
|
||||
3. Apply the variable values defined in the instance 'args' record.
|
||||
This application is treated similarly to the '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'.
|
||||
3. Apply the variable values defined in a instance 'args' record.
|
||||
The 'args' record may have multiple sets of args.
|
||||
If the preset instance includes an 'argsLabel' value then this record
|
||||
is selected to be applied. If No 'argsLabel' is given then
|
||||
the record named 'default' is selected. If there is no record
|
||||
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.
|
||||
are connected to their source variables.
|
||||
@ -518,7 +529,646 @@ before registering the variable.
|
||||
6. The internal variable id map is created to implement fast
|
||||
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 "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwTextBuf.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwAudioDevice.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwTextBuf.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwFile.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwTextBuf.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwB23Tree.h"
|
||||
|
@ -13,16 +13,32 @@ namespace cw
|
||||
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 idLabelPair_t* p = array;
|
||||
for(; p->id != eolId; ++p)
|
||||
if( p->id == id )
|
||||
return p->label;
|
||||
const idLabelPair_t* p = _idToSlot(array,id,eolId);
|
||||
|
||||
return nullptr;
|
||||
return p->label;
|
||||
}
|
||||
|
||||
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 )
|
||||
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 eolId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cw::sleepSec( unsigned secs )
|
||||
{
|
||||
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;
|
||||
|
||||
// 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 );
|
||||
|
||||
// Returns eolId if the id is not found.
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwFile.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwFile.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwUtility.h"
|
||||
#include "cwMath.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
@ -21,9 +22,9 @@ namespace cw
|
||||
{
|
||||
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
|
||||
//
|
||||
|
||||
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>();
|
||||
|
||||
@ -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->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer
|
||||
|
||||
real_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 rmsLin = vop::mean(p->rmsWnd,p->rmsWndCnt); // calc avg RMS
|
||||
coeff_t rmsDb = std::max(-100.0,20 * log10(std::max((coeff_t)0.00001,rmsLin))); // convert avg RMS to dB
|
||||
rmsDb += 100.0;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)));
|
||||
|
||||
@ -170,7 +171,7 @@ void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms )
|
||||
// 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>();
|
||||
|
||||
@ -196,7 +197,7 @@ cw::rc_t cw::dsp::limiter::exec( obj_t* p, const sample_t* x, sample_t* y, unsig
|
||||
}
|
||||
else
|
||||
{
|
||||
real_t T = p->thresh * p->ogain;
|
||||
coeff_t T = p->thresh * p->ogain;
|
||||
|
||||
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
|
||||
//
|
||||
|
||||
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>();
|
||||
|
||||
@ -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 )
|
||||
vop::copy(y,x,n);
|
||||
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;
|
||||
}
|
||||
|
||||
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->bypassFl = bypassFl;
|
||||
@ -272,7 +273,7 @@ cw::rc_t cw::dsp::dc_filter::set( obj_t* p, real_t gain, bool bypassFl )
|
||||
// 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>();
|
||||
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;
|
||||
|
||||
@ -475,7 +476,7 @@ void cw::dsp::audio_meter::reset( obj_t* p )
|
||||
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);
|
||||
|
||||
|
@ -14,36 +14,36 @@ namespace cw
|
||||
|
||||
typedef struct
|
||||
{
|
||||
real_t srate; // system sample rate
|
||||
srate_t srate; // system sample rate
|
||||
unsigned procSmpCnt; // samples per exec cycle
|
||||
real_t inGain; // input gain
|
||||
real_t threshDb; // threshold in dB (max:100 min:0)
|
||||
real_t ratio_num; // numerator of the ratio
|
||||
coeff_t inGain; // input gain
|
||||
coeff_t threshDb; // threshold in dB (max:100 min:0)
|
||||
coeff_t ratio_num; // numerator of the ratio
|
||||
unsigned atkSmp; // time to reduce 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
|
||||
sample_t* rmsWnd; // rmsWnd[rmsWndAllocCnt]
|
||||
unsigned rmsWndAllocCnt; //
|
||||
unsigned rmsWndCnt; // current RMS window size (rmsWndCnt must be <= rmsWndAllocCnt)
|
||||
unsigned rmsWndIdx; // next RMS window input index
|
||||
unsigned state; // env. state
|
||||
real_t rmsDb; // current incoming signal RMS (max:100 min:0)
|
||||
real_t gain; // current compressor gain
|
||||
real_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs.
|
||||
real_t pkDb; //
|
||||
real_t accumDb; //
|
||||
coeff_t rmsDb; // current incoming signal RMS (max:100 min:0)
|
||||
coeff_t gain; // current compressor gain
|
||||
coeff_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs.
|
||||
coeff_t pkDb; //
|
||||
coeff_t accumDb; //
|
||||
|
||||
} 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 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_release_ms( obj_t* p, real_t ms );
|
||||
void set_thresh_db( obj_t* p, real_t thresh );
|
||||
void set_rms_wnd_ms( obj_t* p, real_t ms );
|
||||
void set_attack_ms( obj_t* p, ftime_t ms );
|
||||
void set_release_ms( obj_t* p, ftime_t ms );
|
||||
void set_thresh_db( obj_t* p, coeff_t thresh );
|
||||
void set_rms_wnd_ms( obj_t* p, ftime_t ms );
|
||||
}
|
||||
|
||||
namespace limiter
|
||||
@ -51,13 +51,13 @@ namespace cw
|
||||
typedef struct
|
||||
{
|
||||
unsigned procSmpCnt;
|
||||
real_t igain; // applied before thresholding
|
||||
real_t thresh; // linear (0.0-1.0) threshold.
|
||||
real_t ogain; // applied after thresholding
|
||||
coeff_t igain; // applied before thresholding
|
||||
coeff_t thresh; // linear (0.0-1.0) threshold.
|
||||
coeff_t ogain; // applied after thresholding
|
||||
bool bypassFl;
|
||||
} 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 exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
|
||||
}
|
||||
@ -66,32 +66,32 @@ namespace cw
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
real_t d[2]; //
|
||||
real_t b[1]; //
|
||||
real_t a[1]; // a[dn] feedback coeff's
|
||||
real_t b0; // feedforward coeff 0
|
||||
coeff_t d[2]; //
|
||||
coeff_t b[1]; //
|
||||
coeff_t a[1]; // a[dn] feedback coeff's
|
||||
coeff_t b0; // feedforward coeff 0
|
||||
bool bypassFl;
|
||||
real_t gain;
|
||||
coeff_t gain;
|
||||
} 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 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
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
real_t srate; //
|
||||
srate_t srate; //
|
||||
unsigned maxFrameN; //
|
||||
unsigned chN; // channel count
|
||||
unsigned frameIdx; // next frame to write
|
||||
sample_t* buf; // [ [maxFrameN] [maxFrameN] ]
|
||||
} 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 exec( obj_t* p, const sample_t* buf, unsigned chN, unsigned frameN );
|
||||
@ -107,10 +107,10 @@ namespace cw
|
||||
unsigned maxWndSmpN;
|
||||
unsigned wndSmpN;
|
||||
sample_t* wndV;
|
||||
real_t srate;
|
||||
real_t peakThreshDb;
|
||||
real_t outLin;
|
||||
real_t outDb;
|
||||
srate_t srate;
|
||||
coeff_t peakThreshDb;
|
||||
coeff_t outLin;
|
||||
coeff_t outDb;
|
||||
bool peakFl;
|
||||
bool clipFl;
|
||||
unsigned peakCnt;
|
||||
@ -118,11 +118,11 @@ namespace cw
|
||||
unsigned wi;
|
||||
} 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 exec( obj_t* p, const sample_t* x, unsigned n );
|
||||
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
|
||||
{
|
||||
typedef float real_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 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
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFileSys.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,8 +1,12 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
|
||||
#include "cwTest.h"
|
||||
#include "cwObject.h"
|
||||
|
||||
#include "cwFileSys.h"
|
||||
#include "cwCommonImpl.h"
|
||||
|
||||
#include "cwMem.h"
|
||||
#include "cwString.h"
|
||||
#include "cwText.h"
|
||||
@ -75,7 +79,7 @@ bool cw::filesys::isDir( const char* dir0 )
|
||||
{
|
||||
// if the dir does not exist
|
||||
if( errno == ENOENT )
|
||||
return false;
|
||||
goto errLabel;
|
||||
|
||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'",cwStringNullGuard(dir));
|
||||
goto errLabel;
|
||||
@ -106,7 +110,7 @@ bool cw::filesys::isFile( const char* fn0 )
|
||||
|
||||
// if the file does not exist
|
||||
if( errno == ENOENT )
|
||||
return false;
|
||||
goto errLabel;
|
||||
|
||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
||||
goto errLabel;
|
||||
@ -137,7 +141,7 @@ bool cw::filesys::isLink( const char* fn0 )
|
||||
{
|
||||
// if the file does not exist
|
||||
if( errno == ENOENT )
|
||||
return false;
|
||||
goto errLabel;
|
||||
|
||||
cwLogSysError( kOpFailRC, errno, "'stat' failed on '%s'.",cwStringNullGuard(fn));
|
||||
goto errLabel;
|
||||
@ -893,3 +897,33 @@ cw::rc_t cw::filesys::makeDir( const char* dirStr )
|
||||
|
||||
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 );
|
||||
|
||||
rc_t makeDir( const char* dirStr );
|
||||
|
||||
rc_t test( const test::test_args_t& args );
|
||||
}
|
||||
|
||||
}
|
||||
|
2207
cwFlow.cpp
2207
cwFlow.cpp
File diff suppressed because it is too large
Load Diff
54
cwFlow.h
54
cwFlow.h
@ -8,54 +8,19 @@ namespace cw
|
||||
|
||||
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_external_device( const external_device_t* dev );
|
||||
|
||||
|
||||
rc_t create( handle_t& hRef,
|
||||
const object_t& classCfg,
|
||||
const object_t& networkCfg,
|
||||
external_device_t* deviceA = nullptr,
|
||||
unsigned deviceN = 0);
|
||||
rc_t create( handle_t& hRef,
|
||||
const object_t* classCfg,
|
||||
const object_t* networkCfg,
|
||||
const object_t* subnetCfg = nullptr,
|
||||
const char* projDir = nullptr,
|
||||
external_device_t* deviceA = nullptr,
|
||||
unsigned deviceN = 0);
|
||||
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
@ -65,11 +30,11 @@ namespace cw
|
||||
rc_t exec_cycle( handle_t h );
|
||||
|
||||
// Run the network to completion.
|
||||
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 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_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 );
|
||||
@ -87,7 +52,6 @@ namespace cw
|
||||
void print_class_list( handle_t h );
|
||||
void print_network( handle_t h );
|
||||
|
||||
rc_t test( const object_t* cfg );
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
@ -9,6 +10,8 @@
|
||||
#include "cwMtx.h"
|
||||
#include "cwDspTypes.h" // real_t, sample_t
|
||||
#include "cwDspTransforms.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwMidiDecls.h"
|
||||
#include "cwFlowDecl.h"
|
||||
#include "cwFlow.h"
|
||||
#include "cwFlowTypes.h"
|
||||
@ -28,14 +31,15 @@ namespace cw
|
||||
kFadeOutStateId,
|
||||
};
|
||||
|
||||
// Each duplicated network is represented by a flow_netword_t record in flow_cross_t.netA[].
|
||||
typedef struct flow_network_str
|
||||
{
|
||||
dsp::recorder::obj_t* recorder;
|
||||
|
||||
flow::external_device_t* deviceA;
|
||||
flow::external_device_t* deviceA; // deviceA[ deviceN ] - cloned exteranl device array
|
||||
unsigned deviceN;
|
||||
flow::handle_t flowH;
|
||||
|
||||
flow::handle_t flowH;
|
||||
|
||||
unsigned stateId; // inactive, fade-in, fade-out
|
||||
double fadeGain; // 0 0->1 1->0
|
||||
unsigned fadeSmpN; //
|
||||
@ -47,7 +51,7 @@ namespace cw
|
||||
|
||||
typedef struct flow_cross_str
|
||||
{
|
||||
unsigned cur_idx;
|
||||
unsigned cur_idx; // index of the network currently receiving parameter updates
|
||||
double srate;
|
||||
|
||||
unsigned netN;
|
||||
@ -106,8 +110,21 @@ namespace cw
|
||||
memcpy(devA,srcDevA,devN * sizeof(flow::external_device_t));
|
||||
|
||||
for(unsigned i=0; i<devN; ++i)
|
||||
if( devA[i].typeId == flow::kAudioDevTypeId )
|
||||
devA[i].u.a.abuf = _clone_abuf( srcDevA[i].u.a.abuf );
|
||||
{
|
||||
switch( devA[i].typeId )
|
||||
{
|
||||
case flow::kAudioDevTypeId:
|
||||
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;
|
||||
}
|
||||
@ -130,7 +147,7 @@ namespace cw
|
||||
net->stateId = net_idx == 0 ? kActiveStateId : kInactiveStateId;
|
||||
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;
|
||||
else
|
||||
{
|
||||
@ -203,9 +220,20 @@ namespace cw
|
||||
|
||||
if( net->stateId == kFadeOutStateId && ef == 0.0 )
|
||||
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 )
|
||||
{
|
||||
flow::abuf_t* src = p->deviceA[devIdx].u.a.abuf;
|
||||
@ -216,6 +244,7 @@ namespace cw
|
||||
//_fade_audio( src, dst, net );
|
||||
}
|
||||
|
||||
|
||||
void _zero_audio_output( flow_cross_t* p, flow_network_t* net, unsigned devIdx )
|
||||
{
|
||||
flow::abuf_t* dst = net->deviceA[devIdx].u.a.abuf;
|
||||
@ -378,13 +407,27 @@ cw::rc_t cw::flow_cross::exec_cycle( handle_t h )
|
||||
{
|
||||
flow_network_t* net = p->netA + i;
|
||||
|
||||
// We generally don't want to fade the input because the state
|
||||
// of the network delay lines would then be invalid when the
|
||||
// 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 ) )
|
||||
_update_audio_input( p, p->netA + i, 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
|
||||
// of the network delay lines would then be invalid when the
|
||||
// network is eventually made active again
|
||||
|
||||
// copy audio from the actual audio device to the cloned audio devices
|
||||
_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
|
||||
for(unsigned j=0; j<p->deviceN; ++j)
|
||||
if( p->deviceA[j].typeId == flow::kAudioDevTypeId && cwIsFlag(p->deviceA[j].flags, flow::kOutFl ) )
|
||||
|
61
cwFlowDecl.h
61
cwFlowDecl.h
@ -5,6 +5,67 @@ namespace cw
|
||||
{
|
||||
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 {
|
||||
kPriPresetProbFl = 0x01,
|
||||
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
|
3352
cwFlowProc.cpp
3352
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 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_out { extern class_members_t members; }
|
||||
namespace audioFileIn { extern class_members_t members; }
|
||||
namespace audioFileOut { extern class_members_t members; }
|
||||
namespace audio_file_in { extern class_members_t members; }
|
||||
namespace audio_file_out { extern class_members_t members; }
|
||||
namespace audio_gain { extern class_members_t members; }
|
||||
namespace audio_split { 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 audio_meter { 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 );
|
||||
}
|
||||
}
|
1962
cwFlowTypes.cpp
1962
cwFlowTypes.cpp
File diff suppressed because it is too large
Load Diff
557
cwFlowTypes.h
557
cwFlowTypes.h
@ -3,20 +3,28 @@ namespace cw
|
||||
namespace flow
|
||||
{
|
||||
|
||||
#define kRealTFl kFloatTFl
|
||||
typedef dsp::real_t real_t;
|
||||
typedef dsp::sample_t sample_t;
|
||||
typedef dsp::fd_real_t fd_real_t;
|
||||
typedef dsp::srate_t srate_t;
|
||||
typedef unsigned uint_t;
|
||||
typedef int int_t;
|
||||
typedef dsp::coeff_t coeff_t;
|
||||
typedef dsp::sample_t sample_t;
|
||||
typedef dsp::fd_sample_t fd_sample_t;
|
||||
typedef dsp::srate_t srate_t;
|
||||
typedef dsp::ftime_t ftime_t;
|
||||
typedef unsigned uint_t;
|
||||
typedef int int_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
|
||||
{
|
||||
struct value_str* base;
|
||||
srate_t srate; // signal sample rate
|
||||
unsigned chN; // count of channels
|
||||
unsigned frameN; // count of sample frames per channel
|
||||
@ -24,28 +32,27 @@ namespace cw
|
||||
} abuf_t;
|
||||
|
||||
|
||||
enum {
|
||||
kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz)
|
||||
kAnyChIdx = kInvalidIdx,
|
||||
kLocalValueN = 2
|
||||
};
|
||||
|
||||
typedef struct fbuf_str
|
||||
{
|
||||
struct value_str* base;
|
||||
srate_t srate; // signal sample rate
|
||||
unsigned flags; // See kXXXFbufFl
|
||||
unsigned chN; // count of channels
|
||||
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* hopSmpN_V; // hopSmpN_V[ chN ] hop sample count
|
||||
fd_real_t** magV; // magV[ chN ][ binN ]
|
||||
fd_real_t** phsV; // phsV[ chN ][ binN ]
|
||||
fd_real_t** hzV; // hzV[ chN ][ binN ]
|
||||
fd_sample_t** magV; // magV[ chN ][ binN ]
|
||||
fd_sample_t** phsV; // phsV[ 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)
|
||||
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;
|
||||
|
||||
typedef struct mbuf_str
|
||||
{
|
||||
const midi::ch_msg_t* msgA;
|
||||
unsigned msgN;
|
||||
} mbuf_t;
|
||||
|
||||
enum
|
||||
{
|
||||
kInvalidTFl = 0x00000000,
|
||||
@ -58,17 +65,23 @@ namespace cw
|
||||
kBoolMtxTFl = 0x00000020,
|
||||
kUIntMtxTFl = 0x00000040,
|
||||
kIntMtxTFl = 0x00000080,
|
||||
kRealMtxTFl = 0x00000100,
|
||||
kFloatMtxTFl = 0x00000200,
|
||||
kDoubleMtxTFl= 0x00000400,
|
||||
kFloatMtxTFl = 0x00000100,
|
||||
kDoubleMtxTFl= 0x00000200,
|
||||
|
||||
kABufTFl = 0x00000800,
|
||||
kFBufTFl = 0x00001000,
|
||||
kABufTFl = 0x00000400,
|
||||
kFBufTFl = 0x00000800,
|
||||
kMBufTFl = 0x00001000,
|
||||
kStringTFl = 0x00002000,
|
||||
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
|
||||
@ -76,7 +89,6 @@ namespace cw
|
||||
union {
|
||||
struct mtx::mtx_str< unsigned >* u;
|
||||
struct mtx::mtx_str< int >* i;
|
||||
struct mtx::mtx_str< real_t >* r;
|
||||
struct mtx::mtx_str< float >* f;
|
||||
struct mtx::mtx_str< double >* d;
|
||||
} u;
|
||||
@ -84,21 +96,24 @@ namespace cw
|
||||
|
||||
typedef struct value_str
|
||||
{
|
||||
unsigned flags;
|
||||
unsigned tflag;
|
||||
|
||||
union {
|
||||
bool b;
|
||||
uint_t u;
|
||||
int_t i;
|
||||
float f;
|
||||
double d;
|
||||
|
||||
mtx_t* mtx;
|
||||
bool b;
|
||||
uint_t u;
|
||||
int_t i;
|
||||
float f;
|
||||
double d;
|
||||
|
||||
abuf_t* abuf;
|
||||
fbuf_t* fbuf;
|
||||
mtx_t* mtx;
|
||||
abuf_t* abuf;
|
||||
fbuf_t* fbuf;
|
||||
mbuf_t* mbuf;
|
||||
|
||||
char* s;
|
||||
char* fname;
|
||||
char* s;
|
||||
|
||||
const object_t* cfg;
|
||||
void* p;
|
||||
|
||||
} u;
|
||||
|
||||
@ -106,20 +121,23 @@ namespace cw
|
||||
|
||||
} value_t;
|
||||
|
||||
|
||||
inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->flags,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); }
|
||||
inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->flags,kBoolMtxTFl|kUIntMtxTFl|kIntMtxTFl|kFloatMtxTFl|kDoubleMtxTFl); }
|
||||
|
||||
struct instance_str;
|
||||
struct proc_str;
|
||||
struct variable_str;
|
||||
|
||||
typedef rc_t (*member_func_t)( struct instance_str* ctx );
|
||||
typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var );
|
||||
typedef rc_t (*member_func_t)( struct proc_str* ctx );
|
||||
typedef rc_t (*member_value_func_t)( struct proc_str* ctx, struct variable_str* var );
|
||||
|
||||
// var_desc_t attribute flags
|
||||
enum
|
||||
{
|
||||
kSrcVarFl = 0x01,
|
||||
kSrcOptVarFl = 0x02
|
||||
|
||||
kInvalidVarDescFl = 0x00,
|
||||
kSrcVarDescFl = 0x01,
|
||||
kSrcOptVarDescFl = 0x02,
|
||||
kNoSrcVarDescFl = 0x04,
|
||||
kInitVarDescFl = 0x08,
|
||||
kMultVarDescFl = 0x10,
|
||||
kSubnetOutVarDescFl = 0x20
|
||||
};
|
||||
|
||||
typedef struct class_members_str
|
||||
@ -139,54 +157,84 @@ namespace cw
|
||||
unsigned type; // Value type id (e.g. kBoolTFl, kIntTFl, ...)
|
||||
unsigned flags; // Attributes for this var. (e.g. kSrcVarFl )
|
||||
const char* docText; // User help string for this var.
|
||||
|
||||
char* proxyProcLabel;
|
||||
char* proxyVarLabel;
|
||||
|
||||
struct var_desc_str* link; // class_desc->varDescL list link
|
||||
} var_desc_t;
|
||||
|
||||
typedef struct preset_str
|
||||
typedef struct class_preset_str
|
||||
{
|
||||
const char* label;
|
||||
const object_t* cfg;
|
||||
struct preset_str* link;
|
||||
} preset_t;
|
||||
const char* label;
|
||||
const object_t* cfg;
|
||||
struct class_preset_str* link;
|
||||
} class_preset_t;
|
||||
|
||||
typedef struct class_desc_str
|
||||
{
|
||||
const object_t* cfg; //
|
||||
const char* label; // class label;
|
||||
var_desc_t* varDescL; // varDescA[varDescN] value description list
|
||||
preset_t* presetL; // presetA[ presetN ]
|
||||
class_members_t* members; // member functions for this class
|
||||
const object_t* cfg; // class cfg
|
||||
const char* label; // class label;
|
||||
var_desc_t* varDescL; // varDescL variable description linked on var_desc_t.link
|
||||
class_preset_t* presetL; // presetA[ presetN ]
|
||||
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;
|
||||
|
||||
enum {
|
||||
kInvalidVarFl = 0x00,
|
||||
kLogVarFl = 0x01,
|
||||
kProxiedVarFl = 0x02,
|
||||
kProxiedOutVarFl = 0x04
|
||||
};
|
||||
|
||||
// Note: The concatenation of 'vid' and 'chIdx' should form a unique identifier among all variables
|
||||
// on a given 'instance'.
|
||||
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
|
||||
unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'inst'
|
||||
var_desc_t* varDesc; // the variable description for this 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())
|
||||
value_t* value; // pointer to the value associated with this variable
|
||||
unsigned label_sfx_id; // the label suffix id of this variable or kBaseSfxId if this has no suffix
|
||||
|
||||
unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'proc'
|
||||
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* var_link; // instance.varL link list
|
||||
struct variable_str* connect_link; // list of outgoing connections
|
||||
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)
|
||||
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())
|
||||
struct variable_str* src_var; // pointer to this input variables source link (or null if it uses the local_value)
|
||||
value_t* value; // pointer to the value associated with this variable
|
||||
|
||||
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* 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;
|
||||
|
||||
|
||||
struct network_str;
|
||||
|
||||
typedef struct instance_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; //
|
||||
|
||||
const char* label; // instance label
|
||||
const object_t* inst_cfg; // instance configuration
|
||||
char* label; // instance label
|
||||
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 object_t* arg_cfg; // optional args configuration
|
||||
|
||||
@ -198,39 +246,130 @@ namespace cw
|
||||
unsigned varMapIdN; // max 'vid' among all variables on this instance
|
||||
unsigned varMapN; // varMapN = varMapIdN * varMapChN
|
||||
variable_t** varMapA; // varMapA[ varMapN ] = allows fast lookup from ('vid','chIdx) to variable
|
||||
|
||||
struct network_str* internal_net;
|
||||
|
||||
struct instance_str* link;
|
||||
} 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
|
||||
{
|
||||
const object_t* networkCfg; // complete cfg used to create this network
|
||||
const object_t* flowCfg; // complete cfg used to create this flow
|
||||
|
||||
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
|
||||
|
||||
const object_t* presetCfg; // presets designed for this network
|
||||
|
||||
unsigned framesPerCycle; // sample frames per cycle (64)
|
||||
bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application
|
||||
bool multiSecPresetProbFl; //
|
||||
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.
|
||||
bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application
|
||||
|
||||
class_desc_t* classDescA; //
|
||||
unsigned classDescN; //
|
||||
class_desc_t* classDescA; //
|
||||
unsigned classDescN; //
|
||||
|
||||
external_device_t* deviceA; // deviceA[ deviceN ] external device description array
|
||||
unsigned deviceN; //
|
||||
class_desc_t* subnetDescA; //
|
||||
unsigned subnetDescN; //
|
||||
|
||||
struct instance_str* network_head; // first instance
|
||||
struct instance_str* network_tail; // last insance
|
||||
external_device_t* deviceA; // deviceA[ deviceN ] external device description array
|
||||
unsigned deviceN; //
|
||||
|
||||
const char* proj_dir; // default input/output directory
|
||||
|
||||
network_t net;
|
||||
|
||||
} flow_t;
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// 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 );
|
||||
void abuf_destroy( abuf_t*& buf );
|
||||
@ -238,46 +377,82 @@ namespace cw
|
||||
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 );
|
||||
|
||||
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, 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, 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_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr );
|
||||
void fbuf_destroy( fbuf_t*& buf );
|
||||
fbuf_t* fbuf_duplicate( const fbuf_t* src );
|
||||
|
||||
mbuf_t* mbuf_create( const midi::ch_msg_t* msgA=nullptr, unsigned msgN=0 );
|
||||
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->flags & kABufTFl; }
|
||||
inline bool value_is_fbuf( const value_t* v ) { return v->flags & kFBufTFl; }
|
||||
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 );
|
||||
const char* value_type_flag_to_label( unsigned flag );
|
||||
|
||||
void value_print( const value_t* value, bool info_fl=false);
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Class and Variable Description
|
||||
//
|
||||
|
||||
var_desc_t* var_desc_find( class_desc_t* cd, const char* var_label );
|
||||
rc_t var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef );
|
||||
|
||||
class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label );
|
||||
var_desc_t* var_desc_create( const char* label, const object_t* value_cfg );
|
||||
void var_desc_destroy( var_desc_t* var_desc );
|
||||
|
||||
void class_dict_print( flow_t* p );
|
||||
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 );
|
||||
|
||||
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 );
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
void proc_destroy( proc_t* proc );
|
||||
rc_t proc_validate( proc_t* proc );
|
||||
|
||||
instance_t* instance_find( flow_t* p, const char* inst_label );
|
||||
rc_t instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef );
|
||||
external_device_t* external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl );
|
||||
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 );
|
||||
|
||||
void instance_print( instance_t* inst );
|
||||
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.
|
||||
// Note: `value_cfg` is optional. Set it to NULL to ignore
|
||||
rc_t var_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
|
||||
// Notes:
|
||||
// 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
|
||||
// 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
|
||||
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
|
||||
bool is_connected_to_external_proc( const variable_t* var );
|
||||
// Returns true if this var is connected to a source proc variable
|
||||
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
|
||||
//
|
||||
|
||||
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 >
|
||||
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;
|
||||
variable_t* dummy = nullptr;
|
||||
if((rc = var_register( inst, var_label, vid, chIdx, nullptr, dummy )) == kOkRC )
|
||||
if((rc = _var_reg( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||
if((rc = var_register( proc, var_label, sfx_id, vid, chIdx, nullptr, dummy )) == kOkRC )
|
||||
if((rc = _var_reg( proc, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Call var_register() on a list of variables.
|
||||
template< typename... ARGS >
|
||||
rc_t var_register( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
||||
{ return _var_reg( inst, chIdx, vid, var_label, std::forward<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( proc, chIdx, vid, var_label, sfx_id, std::forward<ARGS>(args)...); }
|
||||
|
||||
|
||||
|
||||
@ -329,28 +531,28 @@ namespace cw
|
||||
// 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>
|
||||
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;
|
||||
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);
|
||||
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 >
|
||||
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;
|
||||
|
||||
if((rc = var_register_and_get( inst, var_label, vid, chIdx, valRef )) == kOkRC )
|
||||
if((rc = _var_reg_and_get( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||
if((rc = var_register_and_get( proc, var_label, sfx_id, vid, chIdx, valRef )) == kOkRC )
|
||||
if((rc = _var_reg_and_get( proc, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
@ -358,8 +560,8 @@ namespace cw
|
||||
|
||||
// Call var_register_and_get() on a list of variables.
|
||||
template< typename... ARGS >
|
||||
rc_t var_register_and_get( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
||||
{ return _var_reg_and_get( inst, chIdx, vid, var_label, std::forward<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( 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.
|
||||
// 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.)
|
||||
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( 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( 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, unsigned frameN );
|
||||
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( 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 >
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -398,66 +602,97 @@ namespace cw
|
||||
|
||||
// Call var_register_and_set() on a list of variables.
|
||||
template< typename... ARGS >
|
||||
rc_t var_register_and_set( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
|
||||
{ return _var_register_and_set( inst, chIdx, vid, var_label, std::forward<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( proc, chIdx, vid, var_label, sfx_id, std::forward<ARGS>(args)...); }
|
||||
|
||||
|
||||
|
||||
void _var_destroy( variable_t* var );
|
||||
|
||||
bool var_exists( instance_t* inst, const char* label, unsigned chIdx );
|
||||
bool var_has_value( 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( 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( 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 );
|
||||
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 );
|
||||
|
||||
|
||||
// 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 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, uint_t& valRef );
|
||||
rc_t var_get( const variable_t* var, int_t& valRef );
|
||||
rc_t var_get( const variable_t* var, float& valRef );
|
||||
rc_t var_get( const variable_t* var, double& valRef );
|
||||
rc_t var_get( const variable_t* var, const char*& valRef );
|
||||
rc_t var_get( const variable_t* var, const 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( variable_t* var, fbuf_t*& 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, int_t& valRef );
|
||||
rc_t var_get( const variable_t* var, float& valRef );
|
||||
rc_t var_get( const variable_t* var, double& valRef );
|
||||
rc_t var_get( const variable_t* var, const char*& valRef );
|
||||
rc_t var_get( const variable_t* var, const 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( 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>
|
||||
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;
|
||||
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);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
var_get(inst,vid,chIdx,value);
|
||||
var_get(proc,vid,chIdx,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 );
|
||||
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( 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( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t* val );
|
||||
//
|
||||
// var_set() coerces the incoming value to the type of the variable (var->type)
|
||||
//
|
||||
|
||||
rc_t var_set_from_cfg( variable_t* var, const object_t* cfg_value );
|
||||
|
||||
rc_t var_set( variable_t* var, const value_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 "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
54
cwIo.cpp
54
cwIo.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwText.h"
|
||||
@ -611,7 +612,7 @@ namespace cw
|
||||
//
|
||||
// MIDI
|
||||
//
|
||||
void _midiCallback( const midi::packet_t* pktArray, unsigned pktCnt )
|
||||
void _midiCallback( void* cbArg, const midi::packet_t* pktArray, unsigned pktCnt )
|
||||
{
|
||||
unsigned i;
|
||||
for(i=0; i<pktCnt; ++i)
|
||||
@ -619,7 +620,7 @@ namespace cw
|
||||
msg_t m;
|
||||
midi_msg_t mm;
|
||||
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;
|
||||
|
||||
|
||||
@ -2114,10 +2115,12 @@ namespace cw
|
||||
rc = cwLogError(rc,"Audio device configuration failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
audio::device::report( p->audioH );
|
||||
|
||||
errLabel:
|
||||
|
||||
if( rc != kOkRC && p->audioH.isValid() )
|
||||
audio::device::report( p->audioH );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2439,7 +2442,8 @@ cw::rc_t cw::io::stop( handle_t h )
|
||||
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;
|
||||
io_t* p = _handleToPtr(h);
|
||||
@ -2447,8 +2451,9 @@ cw::rc_t cw::io::exec( handle_t h, void* execCbArg )
|
||||
if( p->wsUiH.isValid() )
|
||||
{
|
||||
ui::flushCache( ui::ws::uiHandle( p->wsUiH ));
|
||||
|
||||
// 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);
|
||||
@ -2490,14 +2495,23 @@ void cw::io::report( handle_t h )
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
io_t* p = _handleToPtr(h);
|
||||
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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
ui::handle_t uiH;
|
||||
if(_handleToUiHandle(h,uiH) == kOkRC )
|
||||
ui::realTimeReport(uiH);
|
||||
ui::ws::handle_t uiH;
|
||||
if(_handleToWsUiHandle(h,uiH) == kOkRC )
|
||||
ui::ws::realTimeReport(uiH);
|
||||
}
|
||||
|
||||
|
14
cwIo.h
14
cwIo.h
@ -164,14 +164,17 @@ namespace cw
|
||||
rc_t start( handle_t h );
|
||||
rc_t pause( 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().
|
||||
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 );
|
||||
void report( handle_t h );
|
||||
void hardwareReport( handle_t h );
|
||||
void realTimeReport( handle_t h );
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
@ -228,6 +231,11 @@ namespace cw
|
||||
const char* midiDevicePortName( handle_t h, unsigned devIdx, bool inputFl, unsigned portIdx );
|
||||
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 );
|
||||
|
||||
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 midiLoadMsgPacket( handle_t h, const midi::packet_t& pkt ); // Note: Set devIdx/portIdx via pkt.devIdx/pkt.portIdx
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwFileSys.h"
|
||||
@ -1024,8 +1025,16 @@ cw::rc_t cw::io::audio_midi::main( const object_t* cfg )
|
||||
// execute the io framework
|
||||
while( !isShuttingDown(app.ioH))
|
||||
{
|
||||
exec(app.ioH);
|
||||
sleepMs(50);
|
||||
const unsigned wsTimeOutMs = 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:
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwText.h"
|
||||
@ -580,8 +581,16 @@ cw::rc_t cw::audio_midi_app::main( const object_t* cfg )
|
||||
// execute the io framework
|
||||
while( !isShuttingDown(app.ioH))
|
||||
{
|
||||
exec(app.ioH);
|
||||
sleepMs(50);
|
||||
const unsigned wsTimeOutMs = 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:
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwFileSys.h"
|
||||
|
82
cwIoFlow.cpp
82
cwIoFlow.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwFileSys.h"
|
||||
@ -8,6 +9,8 @@
|
||||
#include "cwTime.h"
|
||||
#include "cwVectOps.h"
|
||||
#include "cwMtx.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwMidiDecls.h"
|
||||
|
||||
#include "cwDspTypes.h"
|
||||
#include "cwFlowDecl.h"
|
||||
@ -87,7 +90,7 @@ namespace cw
|
||||
|
||||
mem::release(p->audioGroupA);
|
||||
mem::release(p);
|
||||
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
@ -95,10 +98,13 @@ namespace cw
|
||||
{
|
||||
unsigned devN = 0;
|
||||
|
||||
//devN += midiDeviceCount(p->ioH);
|
||||
devN += socketCount(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)
|
||||
devN += p->audioGroupA[i].iDeviceN + p->audioGroupA[i].oDeviceN;
|
||||
|
||||
@ -109,7 +115,6 @@ namespace cw
|
||||
{
|
||||
dev->ioDevIdx = ioDevIdx;
|
||||
dev->ioDevId = audioDeviceUserId( p->ioH, ioDevIdx );
|
||||
dev->abuf.base = nullptr;
|
||||
dev->abuf.srate = audioDeviceSampleRate( p->ioH, ioDevIdx );
|
||||
dev->abuf.chN = audioDeviceChannelCount( p->ioH, ioDevIdx, inOrOutFl );
|
||||
dev->abuf.frameN = dspFrameCnt;
|
||||
@ -146,23 +151,38 @@ namespace cw
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _setup_device_cfg( flow::external_device_t* d, const char* devLabel, unsigned ioDevId, unsigned typeId, unsigned flags )
|
||||
rc_t _send_midi_triple( flow::external_device_t* dev, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||
{
|
||||
d->label = devLabel;
|
||||
d->ioDevId = ioDevId;
|
||||
d->typeId = typeId;
|
||||
d->flags = flags;
|
||||
return midiDeviceSend(((io_flow_t*)dev->reserved)->ioH, dev->ioDevIdx, dev->ioPortIdx, status |= ch, d0, d1);
|
||||
}
|
||||
|
||||
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->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 )
|
||||
{
|
||||
_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.
|
||||
// This buffer also allows the 'audio_in' and 'audio_out' flow procs to configure themselves.
|
||||
d->u.a.abuf = &ad->abuf;
|
||||
}
|
||||
}
|
||||
|
||||
void _setup_generic_device_array( io_flow_t* p )
|
||||
{
|
||||
@ -175,17 +195,27 @@ namespace cw
|
||||
|
||||
// get serial devices
|
||||
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 );
|
||||
|
||||
// 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 );
|
||||
_setup_device_cfg( p, p->deviceA + i, io::serialDeviceLabel(p->ioH,di), di, flow::kSerialDevTypeId, flow::kInFl | flow::kOutFl );
|
||||
|
||||
// get sockets
|
||||
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
|
||||
for(unsigned gi=0; gi<p->audioGroupN; ++gi)
|
||||
{
|
||||
@ -198,6 +228,9 @@ namespace cw
|
||||
_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 )
|
||||
@ -254,6 +287,18 @@ namespace cw
|
||||
rc_t rc = kOkRC;
|
||||
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( m.iBufChCnt > 0 )
|
||||
{
|
||||
@ -318,6 +363,9 @@ namespace cw
|
||||
}
|
||||
|
||||
errLabel:
|
||||
// Drop the MIDI messages that were processed on this call.
|
||||
midiDeviceClearBuffer(p->ioH,midiBufMsgCnt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwKeyboard.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
@ -118,8 +119,16 @@ cw::rc_t cw::min_test( const object_t* cfg )
|
||||
// execuite the io framework
|
||||
while( !isShuttingDown(app.ioH))
|
||||
{
|
||||
exec(app.ioH);
|
||||
sleepMs(500);
|
||||
const unsigned wsTimeOutMs = 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);
|
||||
|
||||
if( isKeyWaiting() )
|
||||
break;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwNumericConvert.h"
|
||||
@ -47,6 +48,7 @@ namespace cw
|
||||
kPanelDivId = 1000,
|
||||
kQuitBtnId,
|
||||
kIoReportBtnId,
|
||||
kIoHwReportBtnId,
|
||||
kIoRtReportBtnId,
|
||||
kPresetReportBtnId,
|
||||
kMRP_ReportBtnId,
|
||||
@ -161,11 +163,12 @@ namespace cw
|
||||
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
|
||||
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
|
||||
{ kPanelDivId, kIoReportBtnId, "ioReportBtnId" },
|
||||
{ kPanelDivId, kIoRtReportBtnId,"ioRtReportBtnId" },
|
||||
{ kPanelDivId, kIoHwReportBtnId, "ioHwReportBtnId" },
|
||||
{ kPanelDivId, kIoRtReportBtnId, "ioRtReportBtnId" },
|
||||
{ kPanelDivId, kMRP_ReportBtnId, "MRP_ReportBtnId" },
|
||||
{ kPanelDivId, kPresetReportBtnId, "presetReportBtnId" },
|
||||
{ kPanelDivId, kNetPrintBtnId, "netPrintBtnId" },
|
||||
{ kPanelDivId, kReportBtnId, "reportBtnId" },
|
||||
{ kPanelDivId, kPresetReportBtnId, "presetReportBtnId" },
|
||||
{ kPanelDivId, kMRP_ReportBtnId, "MRP_ReportBtnId" },
|
||||
{ kPanelDivId, kLatencyBtnId, "latencyBtnId" },
|
||||
|
||||
{ kPanelDivId, kStartBtnId, "startBtnId" },
|
||||
@ -307,7 +310,7 @@ namespace cw
|
||||
const char* record_fn_ext;
|
||||
const char* record_backup_dir;
|
||||
|
||||
const char* scoreFn;
|
||||
//const char* scoreFn;
|
||||
const object_t* perfDirL;
|
||||
const char* velTableFname;
|
||||
const char* velTableBackupDir;
|
||||
@ -386,6 +389,7 @@ namespace cw
|
||||
|
||||
const char* dflt_perf_label;
|
||||
unsigned dflt_perf_app_id;
|
||||
unsigned run_dur_secs;
|
||||
|
||||
|
||||
} app_t;
|
||||
@ -401,13 +405,13 @@ namespace cw
|
||||
app->record_fn = argv[i+1];
|
||||
goto found_fl;
|
||||
}
|
||||
|
||||
/*
|
||||
if( textCompare(argv[i],"score_fn") == 0 )
|
||||
{
|
||||
app->scoreFn = argv[i+1];
|
||||
goto found_fl;
|
||||
}
|
||||
|
||||
*/
|
||||
if( textCompare(argv[i],"beg_play_loc") == 0 )
|
||||
{
|
||||
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,
|
||||
"record_fn", app->record_fn,
|
||||
"record_fn_ext", app->record_fn_ext,
|
||||
"score_fn", app->scoreFn,
|
||||
//"score_fn", app->scoreFn,
|
||||
"perfDirL", app->perfDirL,
|
||||
"flow_proc_dict_fn", flow_proc_dict_fn,
|
||||
"midi_play_record", app->midi_play_record_cfg,
|
||||
@ -460,6 +464,7 @@ namespace cw
|
||||
"beg_play_loc", app->beg_play_loc,
|
||||
"end_play_loc", app->end_play_loc,
|
||||
"dflt_perf_label", app->dflt_perf_label,
|
||||
"run_dur_secs", app->run_dur_secs,
|
||||
"live_mode_fl", app->useLiveMidiFl,
|
||||
"enable_recording_fl", app->enableRecordFl,
|
||||
"midi_record_dir", midi_record_dir,
|
||||
@ -482,11 +487,13 @@ namespace cw
|
||||
_apply_command_line_args(app,argc,argv);
|
||||
|
||||
|
||||
/*
|
||||
if((app->scoreFn = filesys::expandPath( app->scoreFn )) == nullptr )
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"The score file name is invalid.");
|
||||
goto errLabel;
|
||||
}
|
||||
*/
|
||||
|
||||
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 )
|
||||
{
|
||||
app_t* app = (app_t*)arg;
|
||||
unsigned logUuId = uiFindElementUuId( app->ioH, kLogId);
|
||||
|
||||
uiSetLogLine( app->ioH, logUuId, text );
|
||||
//app_t* app = (app_t*)arg;
|
||||
//unsigned logUuId = uiFindElementUuId( app->ioH, kLogId);
|
||||
|
||||
//uiSetLogLine( app->ioH, logUuId, text );
|
||||
log::defaultOutput(nullptr,level,text);
|
||||
}
|
||||
|
||||
@ -599,7 +606,7 @@ namespace cw
|
||||
|
||||
mem::release((char*&)app.record_backup_dir);
|
||||
mem::release((char*&)app.record_dir);
|
||||
mem::release((char*&)app.scoreFn);
|
||||
//mem::release((char*&)app.scoreFn);
|
||||
mem::release(app.midiRecordDir);
|
||||
mem::release(app.midiLoadFname);
|
||||
vtbl::destroy(app.vtH);
|
||||
@ -725,6 +732,7 @@ namespace cw
|
||||
char* perf_fname = nullptr;
|
||||
char* meta_fname = nullptr;
|
||||
bool skip_fl = false;
|
||||
|
||||
// create the performance recording file path
|
||||
if((perf_fname = filesys::makeFn(dir,fname,nullptr,recording_folder,nullptr)) == nullptr )
|
||||
{
|
||||
@ -796,8 +804,11 @@ namespace cw
|
||||
|
||||
mem::release(meta_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 )
|
||||
@ -1000,9 +1011,9 @@ namespace cw
|
||||
// apply the fragment defined gain settings
|
||||
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_out_gain","gain", flow::kAnyChIdx, (dsp::real_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, "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::coeff_t)frag->ogain );
|
||||
io_flow::set_variable_value( app->ioFlowH, flow_cross::kNextDestId, "wd_bal", "in", flow::kAnyChIdx, (dsp::coeff_t)frag->wetDryGain );
|
||||
|
||||
// activate the cross-fade
|
||||
io_flow::begin_cross_fade( app->ioFlowH, frag->fadeOutMs );
|
||||
@ -1158,8 +1169,6 @@ namespace cw
|
||||
{
|
||||
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 );
|
||||
|
||||
if( f != nullptr )
|
||||
@ -1879,7 +1888,7 @@ namespace cw
|
||||
|
||||
errLabel:
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1966,7 +1975,7 @@ namespace cw
|
||||
// read the preset data file
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2193,7 +2202,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
||||
m[i].id = e->uid;
|
||||
m[i].loc = e->loc;
|
||||
m[i].arg = e;
|
||||
|
||||
|
||||
app->locMap[i].loc = e->loc;
|
||||
app->locMap[i].timestamp = m[i].timestamp;
|
||||
|
||||
@ -2284,7 +2293,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
||||
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;
|
||||
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
|
||||
if( !lockLoctnFl )
|
||||
{
|
||||
app->end_play_loc = app->maxPerfLoc;
|
||||
app->beg_play_loc = app->minPerfLoc;
|
||||
app->end_play_loc = end_loc==score_parse::kInvalidLocId ? app->maxPerfLoc : end_loc;
|
||||
app->beg_play_loc = beg_loc==score_parse::kInvalidLocId ? app->minPerfLoc : beg_loc;
|
||||
}
|
||||
|
||||
// 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 );
|
||||
|
||||
// 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.");
|
||||
goto errLabel;
|
||||
@ -2906,7 +2915,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
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() )
|
||||
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 )
|
||||
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 rc = kOkRC;
|
||||
dsp::real_t value;
|
||||
dsp::ftime_t value;
|
||||
|
||||
if( useLiveMidiFl )
|
||||
{
|
||||
@ -3032,7 +3041,7 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
|
||||
@ -3097,10 +3106,14 @@ rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc);
|
||||
io::report( app->ioH );
|
||||
break;
|
||||
|
||||
case kIoRtReportBtnId:
|
||||
io::realTimeReport(app->ioH);
|
||||
case kIoHwReportBtnId:
|
||||
io::hardwareReport( app->ioH );
|
||||
break;
|
||||
|
||||
case kIoRtReportBtnId:
|
||||
io::realTimeReport( app->ioH );
|
||||
break;
|
||||
|
||||
case kNetPrintBtnId:
|
||||
if( app->ioFlowH.isValid() )
|
||||
io_flow::print_network(app->ioFlowH,flow_cross::kCurDestId);
|
||||
@ -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;
|
||||
ui::appIdMap_t bigMap[ bigMapN ];
|
||||
double sysSampleRate = 0;
|
||||
time::spec_t start_time = time::current_time();
|
||||
|
||||
for(unsigned i=0; i<mapN; ++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
|
||||
while( !io::isShuttingDown(app.ioH))
|
||||
{
|
||||
//time::spec_t t0;
|
||||
//time::get(t0);
|
||||
const unsigned wsTimeOutMs = 50;
|
||||
time::spec_t t0 = time::current_time();
|
||||
|
||||
unsigned timeOutMs = app.psNextFrag != nullptr ? 0 : wsTimeOutMs;
|
||||
|
||||
// This call may block on the websocket handle.
|
||||
io::exec(app.ioH);
|
||||
|
||||
//unsigned dMs = time::elapsedMs(t0);
|
||||
//if( dMs < 50 && app.psNextFrag == nullptr )
|
||||
//{
|
||||
// sleepMs( 50-dMs );
|
||||
//}
|
||||
io::exec(app.ioH,timeOutMs);
|
||||
|
||||
time::spec_t t1 = time::current_time();
|
||||
unsigned dMs = time::elapsedMs(t0,t1);
|
||||
|
||||
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
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwTime.h"
|
||||
|
13
cwIoTest.cpp
13
cwIoTest.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwTime.h"
|
||||
@ -308,8 +309,16 @@ cw::rc_t cw::io::test( const object_t* cfg )
|
||||
// execuite the io framework
|
||||
while( !isShuttingDown(app.ioH))
|
||||
{
|
||||
exec(app.ioH);
|
||||
sleepMs(50);
|
||||
const unsigned wsTimeOutMs = 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:
|
||||
|
15
cwLex.cpp
15
cwLex.cpp
@ -3,7 +3,8 @@
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
|
||||
#include "cwTest.h"
|
||||
#include "cwObject.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;
|
||||
unsigned tid = kInvalidId;
|
||||
@ -866,7 +867,9 @@ namespace cw
|
||||
"/* block \n"
|
||||
"comment */"
|
||||
"\"quoted string\""
|
||||
"ident1"
|
||||
"ident1 "
|
||||
"1234.56f"
|
||||
"345u"
|
||||
" // last line comment";
|
||||
|
||||
// initialize a lexer with a buffer of text
|
||||
@ -884,7 +887,7 @@ namespace cw
|
||||
while( (tid = lex::getNextToken(h)) != kEofLexTId )
|
||||
{
|
||||
// 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::currentColumnNumber(h),
|
||||
lex::idToLabel(h,tid),
|
||||
@ -899,11 +902,9 @@ namespace cw
|
||||
int iv = lex::tokenInt(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
|
||||
if( tid == kErrorLexTId )
|
||||
{
|
||||
|
2
cwLex.h
2
cwLex.h
@ -129,7 +129,7 @@ namespace cw
|
||||
const char* idToLabel( handle_t h, unsigned typeId );
|
||||
|
||||
// Lexer testing stub.
|
||||
rc_t test( );
|
||||
rc_t test( const test::test_args_t& args );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFileSys.h"
|
||||
#include "cwLib.h"
|
||||
|
36
cwLog.cpp
36
cwLog.cpp
@ -2,6 +2,7 @@
|
||||
#include "cwLog.h"
|
||||
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.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, ... )
|
||||
{
|
||||
rc_t rc = returnCode;
|
||||
if( level >= _handleToPtr(h)->level )
|
||||
if( level >= _handleToPtr(h)->level || level == kPrint_LogLevel )
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
@ -146,6 +147,29 @@ unsigned cw::log::flags( handle_t h )
|
||||
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 )
|
||||
{
|
||||
@ -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* label;
|
||||
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
|
||||
label = "<unknown>";
|
||||
|
||||
return label;
|
||||
}
|
||||
{ return idToLabel(logLevelLabelArray,level,kInvalid_LogLevel); }
|
||||
|
||||
|
||||
|
||||
@ -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.
|
||||
if( level == kInfo_LogLevel )
|
||||
if( level == kInfo_LogLevel || level == kPrint_LogLevel )
|
||||
{
|
||||
loStr = "";
|
||||
syStr = "";
|
||||
|
6
cwLog.h
6
cwLog.h
@ -39,6 +39,12 @@ namespace cw
|
||||
void setLevel( handle_t h, unsigned level );
|
||||
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 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 )
|
||||
{
|
||||
return !( (x < 2) || (x & (x-1)) );
|
||||
return x==1 || (!( (x < 2) || (x & (x-1)) ));
|
||||
}
|
||||
|
||||
unsigned cw::math::nextPowerOfTwo( unsigned val )
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
|
||||
#include "cwThread.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwMidi.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwText.h"
|
||||
@ -283,6 +284,7 @@ namespace cw
|
||||
time::spec_t ts;
|
||||
ts.tv_sec = ev->time.time.tv_sec;
|
||||
ts.tv_nsec = ev->time.time.tv_nsec;
|
||||
|
||||
parser::midiTriple(p->prvRcvPort->parserH, &ts, status | ch, d0, d1 );
|
||||
|
||||
p->prvTimeMicroSecs = microSecs1;
|
||||
@ -439,7 +441,7 @@ namespace cw
|
||||
{
|
||||
assert(j<p->devArray[i].iPortCnt);
|
||||
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_cap = caps;
|
||||
p->devArray[i].iPortArray[j].alsa_addr = addr;
|
||||
@ -461,7 +463,7 @@ namespace cw
|
||||
{
|
||||
assert(k<p->devArray[i].oPortCnt);
|
||||
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_cap = caps;
|
||||
p->devArray[i].oPortArray[k].alsa_addr = addr;
|
||||
@ -475,6 +477,11 @@ namespace cw
|
||||
++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:
|
||||
@ -736,7 +743,7 @@ const char* cw::midi::device::alsa::portName( handle_t h, unsigned devIdx,
|
||||
if( cwIsFlag(flags,kInMpFl) )
|
||||
{
|
||||
if( portIdx >= p->devArray[devIdx].iPortCnt )
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return p->devArray[devIdx].iPortArray[portIdx].nameStr;
|
||||
}
|
||||
@ -782,7 +789,7 @@ cw::rc_t cw::midi::device::alsa::send( handle_t h, unsigned devIdx, unsigned po
|
||||
rc_t rc = kOkRC;
|
||||
snd_seq_event_t ev;
|
||||
int arc;
|
||||
alsa_device_t* p = _handleToPtr(h);
|
||||
alsa_device_t* p = _handleToPtr(h);
|
||||
|
||||
assert( p!=NULL && devIdx < p->devCnt && portIdx < p->devArray[devIdx].oPortCnt );
|
||||
|
||||
@ -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_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:
|
||||
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;
|
||||
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,10 @@ namespace cw
|
||||
uint8_t d0; // midi data byte 0
|
||||
uint8_t d1; // midi data byte 1
|
||||
} msg_t;
|
||||
|
||||
|
||||
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 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
|
||||
@ -25,8 +25,19 @@ namespace cw
|
||||
unsigned msgCnt; // Count of mdMsg records or sys-ex bytes
|
||||
} 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
|
||||
|
128
cwMidiDevice.cpp
128
cwMidiDevice.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwObject.h"
|
||||
@ -29,7 +30,7 @@ namespace cw
|
||||
kPausedStateId,
|
||||
kPlayingStateId
|
||||
} transportStateId_t;
|
||||
|
||||
|
||||
typedef struct device_str
|
||||
{
|
||||
cbFunc_t cbFunc;
|
||||
@ -54,6 +55,11 @@ namespace cw
|
||||
unsigned long long offset_micros;
|
||||
unsigned long long last_posn_micros;
|
||||
time::spec_t start_time;
|
||||
|
||||
ch_msg_t* buf;
|
||||
unsigned bufN;
|
||||
std::atomic<unsigned> buf_ii;
|
||||
std::atomic<unsigned> buf_oi;
|
||||
|
||||
} device_t;
|
||||
|
||||
@ -101,9 +107,12 @@ namespace cw
|
||||
rc = cwLogError(rc,"MIDI port thread destroy failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
destroy(p->alsaDevH);
|
||||
destroy(p->fileDevH);
|
||||
|
||||
mem::release(p->buf);
|
||||
mem::release(p);
|
||||
|
||||
errLabel:
|
||||
@ -173,6 +182,45 @@ namespace cw
|
||||
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
|
||||
} // midi
|
||||
@ -188,7 +236,9 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
|
||||
const char* appNameStr,
|
||||
const char* fileDevName,
|
||||
unsigned fileDevReadAheadMicros,
|
||||
unsigned parserBufByteCnt )
|
||||
unsigned parserBufByteCnt,
|
||||
bool enableBufFl,
|
||||
unsigned bufferMsgCnt )
|
||||
{
|
||||
rc_t rc = 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>();
|
||||
|
||||
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.");
|
||||
goto errLabel;
|
||||
@ -206,16 +260,29 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
|
||||
|
||||
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.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
p->cbFunc = cbFunc;
|
||||
p->cbArg = cbArg;
|
||||
p->file_dev_cnt = count(p->fileDevH);
|
||||
p->total_dev_cnt = p->alsa_dev_cnt + p->file_dev_cnt;
|
||||
p->alsaPollfdA = pollFdArray(p->alsaDevH,p->alsaPollfdN);
|
||||
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,
|
||||
_thread_func,
|
||||
@ -257,6 +324,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
|
||||
const char* fileDevName = "file_dev";
|
||||
unsigned fileDevReadAheadMicros = 3000;
|
||||
unsigned parseBufByteCnt = 1024;
|
||||
bool enableBufFl = false;
|
||||
unsigned bufMsgCnt = 0;
|
||||
const object_t* file_ports = nullptr;
|
||||
const object_t* port = nullptr;
|
||||
|
||||
@ -264,6 +333,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
|
||||
"fileDevName",fileDevName,
|
||||
"fileDevReadAheadMicros",fileDevReadAheadMicros,
|
||||
"parseBufByteCnt",parseBufByteCnt,
|
||||
"enableBufFl",enableBufFl,
|
||||
"bufferMsgCnt",bufMsgCnt,
|
||||
"file_ports",file_ports)) != kOkRC )
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@ -437,15 +508,15 @@ const char* cw::midi::device::portName( handle_t h, unsigned devIdx, unsigned
|
||||
const char* name = nullptr;
|
||||
|
||||
if((alsaDevIdx = _devIdxToAlsaDevIdx(p,devIdx)) != kInvalidIdx )
|
||||
name = portName(p->alsaDevH,alsaDevIdx,flags,portIdx);
|
||||
name = portName(p->alsaDevH,alsaDevIdx,flags,portIdx);
|
||||
else
|
||||
if((fileDevIdx = _devIdxToFileDevIdx(p,devIdx)) != kInvalidIdx )
|
||||
name = portName(p->fileDevH,fileDevIdx,flags,portIdx);
|
||||
name = portName(p->fileDevH,fileDevIdx,flags,portIdx);
|
||||
else
|
||||
cwLogError(kInvalidArgRC,"The device index %i is not valid.");
|
||||
|
||||
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;
|
||||
}
|
||||
@ -573,7 +644,7 @@ errLabel:
|
||||
cw::rc_t cw::midi::device::setEndMsg( handle_t h, unsigned devIdx, unsigned portIdx, unsigned msgIdx )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
device_t* p = _handleToPtr(h);
|
||||
device_t* p = _handleToPtr(h);
|
||||
|
||||
if(_devIdxToFileDevIdx(p,devIdx) == kInvalidIdx )
|
||||
{
|
||||
@ -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 )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
@ -668,6 +776,8 @@ cw::rc_t cw::midi::device::report( handle_t h )
|
||||
goto errLabel;
|
||||
|
||||
report(h,tbH);
|
||||
|
||||
printf("%s\n",text(tbH));
|
||||
|
||||
errLabel:
|
||||
destroy(tbH);
|
||||
|
@ -30,7 +30,9 @@ namespace cw
|
||||
const char* appNameStr,
|
||||
const char* fileDevName = "file_dev",
|
||||
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,
|
||||
cbFunc_t cbFunc,
|
||||
@ -47,7 +49,7 @@ namespace cw
|
||||
const char* portName( handle_t h, unsigned devIdx, unsigned flags, unsigned portIdx );
|
||||
unsigned portNameToIndex( handle_t h, unsigned devIdx, unsigned flags, const char* portName );
|
||||
rc_t portEnable( handle_t h, unsigned devIdx, unsigned flags, unsigned portIdx, bool enableFl );
|
||||
|
||||
|
||||
rc_t send( handle_t h, unsigned devIdx, unsigned portIdx, uint8_t st, uint8_t d0, uint8_t d1 );
|
||||
rc_t sendData( handle_t h, unsigned devIdx, unsigned portIdx, const uint8_t* dataPtr, unsigned byteCnt );
|
||||
|
||||
@ -57,6 +59,10 @@ namespace cw
|
||||
rc_t seekToMsg( 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 stop( handle_t h );
|
||||
rc_t pause( handle_t h, bool pause_fl );
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwObject.h"
|
||||
@ -86,7 +87,7 @@ namespace cw
|
||||
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;
|
||||
time::spec_t cur_time = time::current_time();
|
||||
@ -95,7 +96,7 @@ namespace cw
|
||||
{
|
||||
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)
|
||||
if( p->msgArray != NULL )
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwFile.h"
|
||||
@ -428,13 +429,12 @@ namespace cw
|
||||
if( p->cbFunc != nullptr )
|
||||
{
|
||||
packet_t pkt = {};
|
||||
pkt.cbArg = p->cbArg;
|
||||
pkt.devIdx = p->base_dev_idx;
|
||||
pkt.portIdx = file_idx;
|
||||
pkt.msgArray = msgA;
|
||||
pkt.msgCnt = msgN;
|
||||
|
||||
p->cbFunc( &pkt, 1 );
|
||||
p->cbFunc( p->cbArg, &pkt, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwMidi.h"
|
||||
@ -58,8 +59,8 @@ namespace cw
|
||||
cbRecd_t* c = p->cbChain;
|
||||
for(; c!=NULL; c=c->linkPtr)
|
||||
{
|
||||
pkt->cbArg = c->cbDataPtr;
|
||||
c->cbFunc( pkt, pktCnt );
|
||||
//pkt->cbArg = c->cbDataPtr;
|
||||
c->cbFunc( c->cbDataPtr, pkt, pktCnt );
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,10 +103,19 @@ namespace cw
|
||||
// get a pointer to the next msg in the buffer
|
||||
msg_t* msgPtr = (msg_t*)(p->buf + p->bufIdx);
|
||||
|
||||
if( midi::isChStatus(p->status) )
|
||||
{
|
||||
msgPtr->status = p->status & 0xf0;
|
||||
msgPtr->ch = p->status & 0x0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgPtr->status = p->status;
|
||||
msgPtr->ch = 0;
|
||||
}
|
||||
|
||||
// fill the buffer msg
|
||||
msgPtr->timeStamp = *timeStamp;
|
||||
msgPtr->status = p->status & 0xf0;
|
||||
msgPtr->ch = p->status & 0x0f;
|
||||
msgPtr->uid = kInvalidId;
|
||||
|
||||
switch( p->dataCnt )
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwVectOps.h"
|
||||
#include "cwMtx.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwMutex.h"
|
||||
#include "cwTime.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwObject.h"
|
||||
@ -30,12 +31,15 @@ namespace cw
|
||||
|
||||
typedef struct node_str
|
||||
{
|
||||
std::atomic<struct node_str*> next;
|
||||
block_t* block;
|
||||
unsigned blobByteN;
|
||||
std::atomic<struct node_str*> next; // 0
|
||||
block_t* block; // 8
|
||||
unsigned blobByteN; // 16
|
||||
unsigned pad; // 20-24 (mult. of 8)
|
||||
// blob data follows
|
||||
} node_t;
|
||||
|
||||
static_assert( sizeof(node_t) % 8 == 0 );
|
||||
|
||||
typedef struct nbmpscq_str
|
||||
{
|
||||
uint8_t* mem; // Pointer to a single area of memory which holds all blocks.
|
||||
@ -51,6 +55,8 @@ namespace cw
|
||||
std::atomic<node_t*> head; // last-in
|
||||
|
||||
node_t* tail; // first-out
|
||||
|
||||
node_t* peek;
|
||||
|
||||
} nbmpscq_t;
|
||||
|
||||
@ -62,8 +68,18 @@ namespace cw
|
||||
rc_t rc = kOkRC;
|
||||
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->mem);
|
||||
mem::release(p);
|
||||
}
|
||||
return rc;
|
||||
@ -98,6 +114,22 @@ namespace cw
|
||||
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
|
||||
{
|
||||
@ -133,6 +165,19 @@ namespace cw
|
||||
|
||||
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;
|
||||
nbmpscq_t* p = nullptr;
|
||||
unsigned byteN = 0;
|
||||
|
||||
if((rc = destroy(hRef)) != kOkRC )
|
||||
goto errLabel;
|
||||
@ -151,18 +195,18 @@ cw::rc_t cw::nbmpscq::create( handle_t& hRef, unsigned initBlkN, unsigned blkByt
|
||||
|
||||
p->stub = mem::allocZ<node_t>();
|
||||
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->blkN = initBlkN;
|
||||
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);
|
||||
b->buf = (uint8_t*)(b + 1);
|
||||
block_t* b = mem::allocZ<block_t>();
|
||||
b->buf = mem::allocZ<uint8_t>(blkByteN);
|
||||
|
||||
b->bufByteN = blkByteN;
|
||||
|
||||
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;
|
||||
p->blockL = b;
|
||||
|
||||
}
|
||||
|
||||
hRef.set(p);
|
||||
@ -215,6 +260,17 @@ cw::rc_t cw::nbmpscq::push( handle_t h, const void* blob, unsigned blobByteN )
|
||||
// Note that this case will immediately overflow the queue.
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
// 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.");
|
||||
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -274,50 +336,102 @@ cw::rc_t cw::nbmpscq::push( handle_t h, const void* blob, unsigned blobByteN )
|
||||
|
||||
cw::nbmpscq::blob_t cw::nbmpscq::get( handle_t h )
|
||||
{
|
||||
blob_t blob;
|
||||
nbmpscq_t* p = _handleToPtr(h);
|
||||
|
||||
node_t* t = p->tail;
|
||||
node_t* n = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||
|
||||
if( n == nullptr )
|
||||
{
|
||||
blob.blob = nullptr;
|
||||
blob.blobByteN = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
blob.blob = (uint8_t*)(n+1);
|
||||
blob.blobByteN = n->blobByteN;
|
||||
}
|
||||
|
||||
return blob;
|
||||
blob_t blob;
|
||||
nbmpscq_t* p = _handleToPtr(h);
|
||||
|
||||
// We always access the tail element through tail->next.
|
||||
node_t* node = p->tail->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||
|
||||
_init_blob( blob, node );
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
cw::rc_t cw::nbmpscq::advance( handle_t h )
|
||||
{
|
||||
nbmpscq_t* p = _handleToPtr(h);
|
||||
rc_t rc = kOkRC;
|
||||
node_t* t = p->tail;
|
||||
node_t* next = t->next.load(std::memory_order_acquire); // ACQUIRE 'next' from producer
|
||||
cw::nbmpscq::blob_t cw::nbmpscq::advance( handle_t h )
|
||||
{
|
||||
blob_t blob;
|
||||
nbmpscq_t* p = _handleToPtr(h);
|
||||
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
|
||||
|
||||
// We always leave the last element on the queue to act as 'stub'.
|
||||
if( next != nullptr )
|
||||
{
|
||||
p->tail = next;
|
||||
|
||||
block_t* b = next->block;
|
||||
int eleN = b->eleN.fetch_add(-1,std::memory_order_acq_rel);
|
||||
// first 'stub' will not have a valid block pointer
|
||||
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
|
||||
assert( eleN >= 1 );
|
||||
// next was valid and so eleN must be >= 1
|
||||
assert( eleN >= 1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( p->cleanBlkN.load(std::memory_order_relaxed) > 0 )
|
||||
_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 )
|
||||
|
@ -34,30 +34,58 @@ namespace cw
|
||||
namespace nbmpscq
|
||||
{
|
||||
typedef handle<struct nbmpscq_str> handle_t;
|
||||
|
||||
|
||||
rc_t create( handle_t& hRef, unsigned initBlkN, unsigned blkByteN );
|
||||
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
//
|
||||
// Producer Function
|
||||
//
|
||||
|
||||
// push() is called by multiple producer threads to insert
|
||||
// an element in the queue. Note that the 'blob' is copied into
|
||||
// the queue and therefore can be released by the caller.
|
||||
rc_t push( handle_t h, const void* blob, unsigned blobByteN );
|
||||
|
||||
|
||||
//
|
||||
// Consumer Functions
|
||||
//
|
||||
|
||||
typedef struct blob_str
|
||||
{
|
||||
rc_t rc;
|
||||
const void* blob;
|
||||
unsigned blobByteN;
|
||||
} blob_t;
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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 );
|
||||
|
||||
|
167
cwObject.cpp
167
cwObject.cpp
@ -5,6 +5,7 @@
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwLex.h"
|
||||
#include "cwText.h"
|
||||
#include "cwNumericConvert.h"
|
||||
@ -152,37 +153,37 @@ namespace cw
|
||||
void _objTypePrintIndent( const char* text, unsigned indent, const char* indentStr=" " )
|
||||
{
|
||||
for(unsigned i=0; i<indent; ++i)
|
||||
printf("%s",indentStr);
|
||||
printf("%s",text);
|
||||
cwLogPrint("%s",indentStr);
|
||||
cwLogPrint("%s",text);
|
||||
}
|
||||
|
||||
void _objTypePrintChild( const object_t* o, print_ctx_t& c, const char* eolStr=",\n", const char* indentStr=" " )
|
||||
{
|
||||
_objTypePrintIndent(" ",c.indent,indentStr);
|
||||
o->type->print(o,c);
|
||||
printf("%s",eolStr);
|
||||
cwLogPrint("%s",eolStr);
|
||||
}
|
||||
|
||||
void _objTypePrintNull( const object_t* o, print_ctx_t& c ) { printf("NULL "); }
|
||||
void _objTypePrintError( const object_t* o, print_ctx_t& c ) { printf("Error "); }
|
||||
void _objTypePrintChar( const object_t* o, print_ctx_t& c ) { printf("%c",o->u.c); }
|
||||
void _objTypePrintInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i8); }
|
||||
void _objTypePrintUInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u8); }
|
||||
void _objTypePrintInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i16); }
|
||||
void _objTypePrintUInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u16); }
|
||||
void _objTypePrintInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i32); }
|
||||
void _objTypePrintUInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u32); }
|
||||
void _objTypePrintInt64( const object_t* o, print_ctx_t& c ) { printf("%lli", o->u.i64); }
|
||||
void _objTypePrintUInt64( const object_t* o, print_ctx_t& c ) { printf("%lli", o->u.u64); }
|
||||
void _objTypePrintBool( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.b ? "true" : "false"); }
|
||||
void _objTypePrintFloat( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.f); }
|
||||
void _objTypePrintDouble( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.d); }
|
||||
void _objTypePrintString( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.str); }
|
||||
void _objTypePrintVect( const object_t* o, print_ctx_t& c ) { printf("<vect>"); }
|
||||
void _objTypePrintNull( const object_t* o, print_ctx_t& c ) { cwLogPrint("NULL "); }
|
||||
void _objTypePrintError( const object_t* o, print_ctx_t& c ) { cwLogPrint("Error "); }
|
||||
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 ) { cwLogPrint("%i",o->u.i8); }
|
||||
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 ) { cwLogPrint("%i",o->u.i16); }
|
||||
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 ) { cwLogPrint("%i",o->u.i32); }
|
||||
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 ) { cwLogPrint("%lli", o->u.i64); }
|
||||
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 ) { cwLogPrint("%s",o->u.b ? "true" : "false"); }
|
||||
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 ) { cwLogPrint("%f",o->u.d); }
|
||||
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 ) { cwLogPrint("<vect>"); }
|
||||
void _objTypePrintPair( const object_t* o, print_ctx_t& c )
|
||||
{
|
||||
o->u.children->type->print(o->u.children,c);
|
||||
printf(": ");
|
||||
cwLogPrint(": ");
|
||||
o->u.children->sibling->type->print(o->u.children->sibling,c);
|
||||
}
|
||||
|
||||
@ -869,11 +870,17 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case lex::kIntLexTId:
|
||||
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
||||
if( tokenIsUnsigned(lexH) )
|
||||
_objCreateValueNode( cnp, lex::tokenUInt(lexH), "uint" );
|
||||
else
|
||||
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
||||
break;
|
||||
|
||||
case lex::kHexLexTId:
|
||||
@ -907,7 +914,7 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
s[n] = 0;
|
||||
|
||||
//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 );
|
||||
}
|
||||
@ -1007,4 +1014,118 @@ cw::rc_t cw::objectToFile( const char* fn, const object_t* obj )
|
||||
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,
|
||||
|
||||
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.)
|
||||
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.
|
||||
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_dict() const { return type != nullptr && type->id == kDictTId; }
|
||||
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_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; }
|
||||
|
||||
rc_t value( void* dst, unsigned dstTypeId );
|
||||
@ -199,7 +207,115 @@ namespace cw
|
||||
const struct object_str* next_child_ele( const struct object_str* ele) const;
|
||||
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 'kOptionalFl' if the label is optional and may not exist.
|
||||
template< typename T >
|
||||
@ -344,6 +460,8 @@ namespace cw
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwFile.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
103
cwPresetSel.cpp
103
cwPresetSel.cpp
@ -1,16 +1,18 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwVectOps.h"
|
||||
#include "cwMidi.h"
|
||||
#include "cwMidiDecls.h"
|
||||
#include "cwFlowDecl.h"
|
||||
#include "cwPresetSel.h"
|
||||
#include "cwFile.h"
|
||||
|
||||
#include "cwMidi.h"
|
||||
#include "cwDynRefTbl.h"
|
||||
#include "cwScoreParse.h"
|
||||
#include "cwSfScore.h"
|
||||
@ -104,38 +106,52 @@ namespace cw
|
||||
return kInvalidIdx;
|
||||
}
|
||||
|
||||
|
||||
rc_t _delete_fragment( preset_sel_t* p, unsigned fragId )
|
||||
{
|
||||
frag_t* f0 = nullptr;
|
||||
frag_t* f1 = p->fragL;
|
||||
|
||||
for(; f1!=nullptr; f1=f1->link)
|
||||
{
|
||||
if( f1->fragId == fragId )
|
||||
{
|
||||
if( f0 == nullptr )
|
||||
p->fragL = f1->link;
|
||||
else
|
||||
f0->link = f1->link;
|
||||
|
||||
for(unsigned i=0; i<f1->presetN; ++i)
|
||||
mem::release(f1->presetA[i].alt_str);
|
||||
rc_t _delete_fragment( preset_sel_t* p, unsigned fragId )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
frag_t* f = p->fragL;
|
||||
|
||||
for(; f!=nullptr; f=f->link)
|
||||
{
|
||||
if( f->fragId == fragId )
|
||||
{
|
||||
// if this is the first frag in the list
|
||||
if( f->prev == nullptr )
|
||||
p->fragL = f->link;
|
||||
else
|
||||
{
|
||||
|
||||
// link the prev fragment to the next fragment
|
||||
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
|
||||
mem::release(f1->note);
|
||||
mem::release(f1->presetA);
|
||||
mem::release(f1);
|
||||
|
||||
return kOkRC;
|
||||
mem::release(f->note);
|
||||
mem::release(f->presetA);
|
||||
mem::release(f->altPresetIdxA);
|
||||
//mem::release(f->multiPresetA);
|
||||
mem::release(f);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
f0 = f1;
|
||||
}
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
rc = cwLogError(kEleNotFoundRC,"The fragment with id %i was not found.",fragId);
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void _destroy_all_frags( preset_sel_t* p )
|
||||
{
|
||||
while( p->fragL != nullptr)
|
||||
@ -245,7 +261,7 @@ namespace cw
|
||||
else
|
||||
{
|
||||
unsigned alt_strN = textLength(alt_str);
|
||||
char alt_str_buf[ alt_strN+1 ] = {0};
|
||||
char alt_str_buf[ alt_strN+1 ];
|
||||
unsigned asi = 0;
|
||||
|
||||
// clear the alt's pointing to the selected preset - because the 'alt_str' has changed
|
||||
@ -260,6 +276,9 @@ namespace cw
|
||||
assert( asi < alt_strN );
|
||||
alt_str_buf[ asi++ ] = alt_str[i];
|
||||
}
|
||||
|
||||
assert( asi <= alt_strN );
|
||||
alt_str_buf[asi] = 0;
|
||||
|
||||
// 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);
|
||||
@ -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 )
|
||||
{
|
||||
preset_sel_t* p = _handleToPtr(h);
|
||||
frag_t* f = p->fragL;
|
||||
|
||||
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);
|
||||
return _delete_fragment(p,fragId);
|
||||
}
|
||||
|
||||
bool cw::preset_sel::is_fragment_end_loc( handle_t h, unsigned loc )
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwFile.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.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* 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);
|
||||
|
||||
return label;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwText.h"
|
||||
#include "cwObject.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwText.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.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 )
|
||||
{ return _nextNonWhiteChar(s,true); }
|
||||
|
||||
const char* cw::firstMatchChar( const char* s, char c )
|
||||
char* cw::firstMatchChar( char* s, char c )
|
||||
{
|
||||
if( s == nullptr )
|
||||
return nullptr;
|
||||
@ -157,7 +157,12 @@ const char* cw::firstMatchChar( const char* s, char c )
|
||||
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;
|
||||
|
||||
@ -168,13 +173,18 @@ const char* cw::lastMatchChar( const char* s, char c )
|
||||
if( sn == 0 )
|
||||
return nullptr;
|
||||
|
||||
for(const char* s1=s+(sn-1); s<=s1; --s1)
|
||||
for(char* s1=s+(sn-1); s<=s1; --s1)
|
||||
if( *s1 == c )
|
||||
return s1;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* cw::lastMatchChar( const char* s, char c )
|
||||
{
|
||||
return lastMatchChar((char*)s,c);
|
||||
}
|
||||
|
||||
bool cw::isInteger( const char* s )
|
||||
{
|
||||
for(; *s; ++s)
|
||||
|
5
cwText.h
5
cwText.h
@ -8,7 +8,7 @@ namespace cw
|
||||
unsigned textLength( const char* s );
|
||||
|
||||
// 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 src is null then dst[0] = 0.
|
||||
// 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
|
||||
// if 'c' does not occur in s[]
|
||||
char* firstMatchChar( char* s, char c );
|
||||
const char* firstMatchChar( const char* s, char c );
|
||||
|
||||
// Find the last occurrent of 'c' in s[].
|
||||
char* lastMatchChar( char* s, char c );
|
||||
const char* lastMatchChar( const char* s, char c );
|
||||
|
||||
bool isInteger( const char* ); // text contains only [0-9]
|
||||
|
15
cwTime.cpp
15
cwTime.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwTime.h"
|
||||
|
||||
#ifdef OS_OSX
|
||||
@ -399,7 +400,7 @@ unsigned cw::time::formatDateTime( char* buffer, unsigned bufN, bool includeDate
|
||||
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;
|
||||
@ -410,15 +411,15 @@ cw::rc_t cw::time::test()
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
printf("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
||||
cwLogPrint("%li %li\n",t0.tv_sec,t0.tv_nsec);
|
||||
|
||||
|
||||
time::get(t0);
|
||||
@ -429,11 +430,11 @@ cw::rc_t cw::time::test()
|
||||
|
||||
int usec = time::elapsedMicros(t0,t1);
|
||||
|
||||
printf("usec:%i\n",usec);
|
||||
cwLogPrint("usec:%i\n",usec);
|
||||
|
||||
t0 = current_time();
|
||||
sleepMs(1000);
|
||||
printf("sleep %i ms\n",elapsedMs(t0));
|
||||
cwLogPrint("sleep %i ms\n",elapsedMs(t0));
|
||||
|
||||
|
||||
return kOkRC;
|
||||
|
2
cwTime.h
2
cwTime.h
@ -85,7 +85,7 @@ namespace cw
|
||||
// Return count of bytes in in buf[]
|
||||
unsigned formatDateTime( char* buf, unsigned bufN, bool includeDateFl=false );
|
||||
|
||||
rc_t test();
|
||||
rc_t test( const test::test_args_t& test );
|
||||
|
||||
//)
|
||||
|
||||
|
152
cwUi.cpp
152
cwUi.cpp
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwFileSys.h"
|
||||
@ -117,7 +118,7 @@ namespace cw
|
||||
unsigned sentMsgN;
|
||||
unsigned recvMsgN;
|
||||
|
||||
bucket_t hashA[ hashN ];
|
||||
bucket_t hashA[ hashN+1 ];
|
||||
|
||||
} ui_t;
|
||||
|
||||
@ -129,7 +130,11 @@ namespace cw
|
||||
assert( parentUuId != kInvalidId && appId != kInvalidId );
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -225,6 +230,18 @@ namespace cw
|
||||
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->eleA);
|
||||
mem::release(p->buf);
|
||||
@ -2219,6 +2236,7 @@ void cw::ui::realTimeReport( handle_t h )
|
||||
{
|
||||
ui_t* p = _handleToPtr(h);
|
||||
printf("UI msg count: recv:%i send:%i\n",p->recvMsgN,p->sentMsgN);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2235,7 +2253,6 @@ namespace cw
|
||||
void* cbArg;
|
||||
uiCallback_t uiCbFunc;
|
||||
websock::cbFunc_t wsCbFunc;
|
||||
unsigned wsTimeOutMs;
|
||||
unsigned idleMsgPeriodMs;
|
||||
time::spec_t lastRecvMsgTimeStamp;
|
||||
} ui_ws_t;
|
||||
@ -2289,7 +2306,7 @@ namespace cw
|
||||
ui_ws_t* p = static_cast<ui_ws_t*>(cbArg);
|
||||
return websock::send( p->wsH, kUiProtocolId, wsSessId, msg, msgByteN );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2317,13 +2334,18 @@ cw::rc_t cw::ui::ws::parseArgs( const object_t& o, args_t& args, const char* ob
|
||||
"rcvBufByteN", args.rcvBufByteN,
|
||||
"xmtBufByteN", args.xmtBufByteN,
|
||||
"fmtBufByteN", args.fmtBufByteN,
|
||||
"websockTimeOutMs", args.wsTimeOutMs,
|
||||
"idleMsgPeriodMs", args.idleMsgPeriodMs,
|
||||
"queueBlkCnt", args.queueBlkCnt,
|
||||
"queueBlkByteCnt", args.queueBlkByteCnt,
|
||||
"uiCfgFn", uiCfgFn )) != kOkRC )
|
||||
{
|
||||
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
|
||||
if((physRootDir = filesys::expandPath( args.physRootDir)) == nullptr )
|
||||
{
|
||||
@ -2374,11 +2396,12 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
||||
appIdMapN,
|
||||
wsCbFunc,
|
||||
args.dfltPageFn,
|
||||
args.wsTimeOutMs,
|
||||
args.idleMsgPeriodMs,
|
||||
args.rcvBufByteN,
|
||||
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,
|
||||
websock::cbFunc_t wsCbFunc,
|
||||
const char* dfltPageFn,
|
||||
unsigned websockTimeOutMs,
|
||||
unsigned idleMsgPeriodMs,
|
||||
unsigned rcvBufByteN,
|
||||
unsigned xmtBufByteN,
|
||||
unsigned fmtBufByteN )
|
||||
unsigned fmtBufByteN,
|
||||
unsigned queueBlkCnt,
|
||||
unsigned queueBlkByteCnt )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
@ -2416,7 +2440,7 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
||||
void* wsCbA = wsCbFunc==nullptr ? p : cbArg;
|
||||
|
||||
// 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.");
|
||||
goto errLabel;
|
||||
@ -2432,7 +2456,6 @@ cw::rc_t cw::ui::ws::create( handle_t& h,
|
||||
p->cbArg = cbArg;
|
||||
p->uiCbFunc = uiCbFunc;
|
||||
p->wsCbFunc = wsCbFunc;
|
||||
p->wsTimeOutMs = websockTimeOutMs;
|
||||
p->idleMsgPeriodMs = idleMsgPeriodMs;
|
||||
// initialize the last received msg
|
||||
time::get(p->lastRecvMsgTimeStamp);
|
||||
@ -2465,13 +2488,13 @@ cw::rc_t cw::ui::ws::destroy( handle_t& h )
|
||||
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);
|
||||
rc_t rc = kOkRC;
|
||||
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.");
|
||||
|
||||
// make the idle callback
|
||||
@ -2486,6 +2509,7 @@ cw::rc_t cw::ui::ws::exec( handle_t h )
|
||||
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 )
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -2519,6 +2550,7 @@ namespace cw
|
||||
{
|
||||
ws::handle_t wsUiH;
|
||||
thread::handle_t thH;
|
||||
unsigned wsTimeOutMs;
|
||||
} ui_ws_srv_t;
|
||||
|
||||
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);
|
||||
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.");
|
||||
}
|
||||
@ -2554,20 +2586,51 @@ 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,
|
||||
unsigned port,
|
||||
const char* physRootDir,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const object_t* uiRsrc,
|
||||
const appIdMap_t* appIdMapA,
|
||||
unsigned appIdMapN,
|
||||
websock::cbFunc_t wsCbFunc,
|
||||
const char* dfltPageFn,
|
||||
unsigned websockTimeOutMs,
|
||||
unsigned rcvBufByteN,
|
||||
unsigned xmtBufByteN,
|
||||
unsigned fmtBufByteN )
|
||||
unsigned port,
|
||||
const char* physRootDir,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const object_t* uiRsrc,
|
||||
const appIdMap_t* appIdMapA,
|
||||
unsigned appIdMapN,
|
||||
unsigned wsTimeOutMs,
|
||||
websock::cbFunc_t wsCbFunc,
|
||||
const char* dfltPageFn,
|
||||
unsigned idleMsgPeriodMs,
|
||||
unsigned rcvBufByteN,
|
||||
unsigned xmtBufByteN,
|
||||
unsigned fmtBufByteN,
|
||||
unsigned queueBlkCnt,
|
||||
unsigned queueBlkByteCnt )
|
||||
{
|
||||
rc_t rc = 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>();
|
||||
|
||||
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.");
|
||||
goto errLabel;
|
||||
@ -2587,6 +2650,8 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
p->wsTimeOutMs = wsTimeOutMs;
|
||||
|
||||
h.set(p);
|
||||
|
||||
errLabel:
|
||||
@ -2596,32 +2661,6 @@ cw::rc_t cw::ui::srv::create( handle_t& h,
|
||||
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 )
|
||||
{
|
||||
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);
|
||||
return ws::uiHandle(p->wsUiH);
|
||||
}
|
||||
|
||||
|
57
cwUi.h
57
cwUi.h
@ -192,8 +192,9 @@ namespace cw
|
||||
unsigned rcvBufByteN;
|
||||
unsigned xmtBufByteN;
|
||||
unsigned fmtBufByteN;
|
||||
unsigned wsTimeOutMs;
|
||||
unsigned idleMsgPeriodMs; // min period without messages before an idle message is generated
|
||||
unsigned queueBlkCnt;
|
||||
unsigned queueBlkByteCnt;
|
||||
} args_t;
|
||||
|
||||
rc_t parseArgs( const object_t& o, args_t& args, const char* object_label="ui" );
|
||||
@ -218,20 +219,20 @@ namespace cw
|
||||
unsigned appIdMapN = 0,
|
||||
websock::cbFunc_t wsCbFunc = nullptr,
|
||||
const char* dfltPageFn = "index.html",
|
||||
unsigned websockTimeOutMs = 50,
|
||||
unsigned idleMsgPeriodMs = 50,
|
||||
unsigned rcvBufByteN = 1024,
|
||||
unsigned xmtBufByteN = 1024,
|
||||
unsigned fmtBufByteN = 4096
|
||||
);
|
||||
unsigned fmtBufByteN = 4096,
|
||||
unsigned queueBlkCnt = 4,
|
||||
unsigned queueBlkByteCnt = 4096 );
|
||||
|
||||
rc_t destroy( handle_t& h );
|
||||
|
||||
// This function should be called periodically to send and receive
|
||||
// queued messages to and from the websocket.
|
||||
// Note that this call may block for up to 'wsTimeOutMs' milliseconds
|
||||
// on the websocket handle.
|
||||
rc_t exec( handle_t h );
|
||||
// while waiting for incoming websocket messages.
|
||||
rc_t exec( handle_t h, unsigned wsTimeOutMs );
|
||||
|
||||
// This function executes the internal default 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 );
|
||||
ui::handle_t uiHandle( handle_t h );
|
||||
void realTimeReport( handle_t h );
|
||||
|
||||
}
|
||||
|
||||
namespace srv
|
||||
@ -248,27 +251,31 @@ namespace cw
|
||||
typedef handle<struct ui_ws_srv_str> handle_t;
|
||||
|
||||
rc_t create( handle_t& h,
|
||||
const ws::args_t& args,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const appIdMap_t* appIdMapA = nullptr,
|
||||
unsigned appIdMapN = 0,
|
||||
websock::cbFunc_t wsCbFunc = nullptr );
|
||||
const ws::args_t& args,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const appIdMap_t* appIdMapA = nullptr,
|
||||
unsigned appIdMapN = 0,
|
||||
unsigned wsTimeOutMs = 50,
|
||||
websock::cbFunc_t wsCbFunc = nullptr );
|
||||
|
||||
rc_t create( handle_t& h,
|
||||
unsigned port,
|
||||
const char* physRootDir,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const object_t* uiRsrc = nullptr,
|
||||
const appIdMap_t* appIdMapA = nullptr,
|
||||
unsigned appIdMapN = 0,
|
||||
websock::cbFunc_t wsCbFunc = nullptr,
|
||||
const char* dfltPageFn = "index.html",
|
||||
unsigned websockTimeOutMs = 50,
|
||||
unsigned rcvBufByteN = 1024,
|
||||
unsigned xmtBufByteN = 1024,
|
||||
unsigned fmtBufByteN = 4096 );
|
||||
unsigned port,
|
||||
const char* physRootDir,
|
||||
void* cbArg,
|
||||
uiCallback_t uiCbFunc,
|
||||
const object_t* uiRsrc = nullptr,
|
||||
const appIdMap_t* appIdMapA = nullptr,
|
||||
unsigned appIdMapN = 0,
|
||||
unsigned wsTimeOutMs = 50,
|
||||
websock::cbFunc_t wsCbFunc = nullptr,
|
||||
const char* dfltPageFn = "index.html",
|
||||
unsigned idleMsgPeriodMs = 50,
|
||||
unsigned rcvBufByteN = 1024,
|
||||
unsigned xmtBufByteN = 1024,
|
||||
unsigned fmtBufByteN = 4096,
|
||||
unsigned queueBlkCnt = 4,
|
||||
unsigned queueBlkByteCnt = 4096 );
|
||||
|
||||
|
||||
rc_t destroy( handle_t& h );
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTest.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwThread.h"
|
||||
#include "cwWebSock.h"
|
||||
@ -378,8 +379,9 @@ namespace cw
|
||||
|
||||
cw::rc_t cw::ui::test( const object_t* cfg )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
ui::ws::args_t args = {};
|
||||
rc_t rc = kOkRC;
|
||||
unsigned wsTimeOutMs = 50;
|
||||
ui::ws::args_t args = {};
|
||||
|
||||
// Application Id's for the resource based UI elements.
|
||||
appIdMap_t mapA[] =
|
||||
@ -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";
|
||||
|
||||
// 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;
|
||||
|
||||
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