caw : Initial working version.

This commit is contained in:
kevin 2024-05-29 19:33:02 -04:00
parent f566198285
commit 35f3637aed
13 changed files with 1158 additions and 295 deletions

View File

@ -65,29 +65,29 @@ include src/libcw/Makefile.am
#lib_LTLIBRARIES += libcw.la #lib_LTLIBRARIES += libcw.la
#include_HEADERS += $(libcwHDR) #include_HEADERS += $(libcwHDR)
src_proj_proj_SOURCES = $(libcwHDR) $(libcwSRC) src/proj/main.cpp src_caw_caw_SOURCES = $(libcwHDR) $(libcwSRC) src/caw/main.cpp
# 1) autoconfig manual recommends setting direct referenes to non-3rd party libraries rather than using -L and -l # 1) autoconfig manual recommends setting direct referenes to non-3rd party libraries rather than using -L and -l
# 2) -ldl is required for dlopen(),dlclose() ... # 2) -ldl is required for dlopen(),dlclose() ...
# src_proj_proj_LDADD = libcw.la -lpthread -ldl # src_caw_caw_LDADD = libcw.la -lpthread -ldl
src_proj_proj_LDADD = -lpthread -ldl src_caw_caw_LDADD = -lpthread -ldl
if cwFFTW if cwFFTW
src_proj_proj_LDADD += -lfftw3 -lfftw3f src_caw_caw_LDADD += -lfftw3 -lfftw3f
endif endif
if cwWEB if cwWEB
src_proj_proj_LDADD += -lfftw3 -lfftw3f src_caw_caw_LDADD += -lfftw3 -lfftw3f
endif endif
if cwWEBSOCK if cwWEBSOCK
src_proj_proj_LDADD += -lwebsockets src_caw_caw_LDADD += -lwebsockets
endif endif
# src_proj_proj_CPPFLAGS = -I$(srcdir)/src/libcw $(AM_CPPFLAGS) # src_caw_caw_CPPFLAGS = -I$(srcdir)/src/libcw $(AM_CPPFLAGS)
bin_PROGRAMS += src/proj/proj bin_PROGRAMS += src/caw/caw
# ${exec_prefix} is the install prefix given to 'configure' by the user. # ${exec_prefix} is the install prefix given to 'configure' by the user.
# ${srcdir} is the directory of this Makefile and is set by autoconf. # ${srcdir} is the directory of this Makefile and is set by autoconf.

View File

@ -3,9 +3,9 @@
# this configure.ac or any of the Makefile.am files. # this configure.ac or any of the Makefile.am files.
# #
AC_COPYRIGHT([Copyright (C) 2019-2022 Kevin Larke]) AC_COPYRIGHT([Copyright (C) 2019-2024 Kevin Larke])
AC_INIT([proj],[1.0],[proj@larke.org]) AC_INIT([caw],[1.0],[caw@larke.org])
AC_CONFIG_SRCDIR([src/proj/main.cpp]) AC_CONFIG_SRCDIR([src/caw/main.cpp])
AC_CONFIG_AUX_DIR([build-aux]) # put aux files in build-aux AC_CONFIG_AUX_DIR([build-aux]) # put aux files in build-aux
AM_INIT_AUTOMAKE([1.9 -Wall foreign subdir-objects]) # subdir-objects needed for non-recursive make AM_INIT_AUTOMAKE([1.9 -Wall foreign subdir-objects]) # subdir-objects needed for non-recursive make
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])

644
examples/proc_dict.cfg Normal file
View File

@ -0,0 +1,644 @@
{
balance: {
vars: {
in: { type:coeff, value:0.5, doc:"Input vaue" },
out: { type:coeff, doc:"Ouput value. Same as input value."},
inv_out: { type:coeff, doc:"1.0 minus output value."}
}
}
audio_in: {
vars: {
dev_label: { type:string, doc:"Audio device label." },
out: { type:audio, doc:"Audio output" },
}
}
audio_out: {
vars: {
dev_label: { type:string, doc:"Audio device label." },
in: { type:audio, flags:["src"], doc:"Audio input." }
}
}
audio_file_in: {
vars: {
fname: { type:string, doc:"Audio file name." },
out:{ type:audio, doc:"Audio file output" },
on_off:{ type:bool, value:false, doc:"1=on 0=off" },,
seekSecs:{ type:ftime, value:0.0, doc:"Seek to the specified seconds offset." }
eofFl:{ type:bool, value: true, doc:"Set the system 'halt' flag when the audio is completely read."},
}
}
audio_file_out: {
vars: {
fname: { type:string, doc:"Audio file name." },
bits: { type:uint, value:32u, doc:"Audio file word width. (8,16,24,32,0=float32)."},
in: { type:audio, flags:["src"], doc:"Audio file input." }
}
}
audio_gain: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
gain: { type:coeff, value:1.0, doc:"Gain coefficient." }
out: { type:audio, doc:"Audio output." },
}
}
audio_split: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
select: { type:int, doc:"Give a list of integers where each integer selects an output channel for the associated input channel." }
igain: { type:coeff, value:1.0, doc:"Audio gain for each input channel." }
ogain: { type:coeff, value:1.0, doc:"Audio gain for each output channel." }
out: { type:audio, doc:"Audio output." },
}
presets:
{
mute_off: { gain:1 },
mute_on: { gain:0 },
}
}
audio_duplicate: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input."},
duplicate: { type: uint, doc:"Count of times to repeat this channel." },
gain: { type: coeff, value:1.0, doc:"Audio gain." },
out: { type:audio, doc:"Audio output containing repeat * input channel count channels."}
}
}
audio_merge: {
vars: {
in0: { type:audio, flags:["src"], doc:"First audio input." },
in1: { type:audio, flags:["src"], doc:"Second audio input." },
in2: { type:audio, flags:["src","src_opt"], doc:"Third audio input." },
in3: { type:audio, flags:["src","src_opt"], doc:"Fourth audio input." },
in4: { type:audio, flags:["src","src_opt"], doc:"Fifth audio input." },
in5: { type:audio, flags:["src","src_opt"], doc:"Sixth audio input." },
in6: { type:audio, flags:["src","src_opt"], doc:"Seventh audio input." },
in7: { type:audio, flags:["src","src_opt"], doc:"Eigth audio input." },
gain: { type:coeff, value:1.0, doc:"Audio gain for each selected (output) channel." }
out: { type:audio, doc:"Audio output. Channel count is the sum of the input channel count." },
}
}
audio_mix: {
vars: {
in0: { type:audio, flags:["src"], doc:"First audio input." },
in1: { type:audio, flags:["src"], doc:"Second audio input." },
gain0: { type:coeff, value:0.5, doc:"Audio gain for input 0." },
gain1: { type:coeff, value:0.5, doc:"Audio gain for input 1." },
out: { type:audio, doc:"Audio output. Channel count is max of the input signal channels." },
}
}
audio_delay: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
maxDelayMs: { type:ftime, value:1000.0 doc:"Maximum possible delay in milliseconds." },
delayMs: { type:ftime, doc:"Delay in milliseconds." },
out: { type:audio, doc:"Audio output." },
}
}
sine_tone: {
vars: {
srate: { type:srate, value:0, doc:"Sine tone sample rate. 0=Use default system sample rate"}
chCnt: { type:uint, value:2, doc:"Output signal channel count."},
hz: { type:coeff, value:440.0, doc:"Frequency in Hertz."},
phase: { type:coeff, value:0.0, doc:"Offset phase in radians."},
dc: { type:coeff, value:0.0, doc:"DC offset applied after gain."},
gain: { type:coeff, value:0.8, doc:"Signal frequency."},
out: { type:audio, doc:"Audio output" },
}
presets: {
a220 : { hz:220 },
a440 : { hz:440 },
a880 : { hz:880 },
}
}
pv_analysis: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
maxWndSmpN: { type:uint, value: 512, doc:"Maximum window sample count." },
wndSmpN: { type:uint, value: 512, doc:"Window sample count." },
hopSmpN: { type:uint, value: 128, doc:"Hop sample count." },
hzFl: { type:bool, value: false, doc:"Calculate frequency via the method of phase changeof each bin." },
out: { type:spectrum, doc:"Spectrum output." }
}
presets: {
dry: {
wndSmpN: 512,
hopSmpN: 128
}
kc: {
wndSmpN: 512,
hopSmpN: 128
}
a: {
wndSmpN: 512,
hopSmpN: 128
}
b: {
wndSmpN: 512,
hopSmpN: 128
}
c: {
wndSmpN: 512,
hopSmpN: 128
}
d: {
wndSmpN: 512,
hopSmpN: 128
}
f_1: {
wndSmpN: 512,
hopSmpN: 128
}
f_2: {
wndSmpN: 512,
hopSmpN: 128
}
f_3: {
wndSmpN: 512,
hopSmpN: 128
}
f_4: {
wndSmpN: 512,
hopSmpN: 128
}
g: {
wndSmpN: 512,
hopSmpN: 128
}
g_a: {
wndSmpN: 512,
hopSmpN: 128
}
g_1_a: {
wndSmpN: 512,
hopSmpN: 128
}
g_1_d: {
wndSmpN: 512,
hopSmpN: 128
}
}
}
pv_synthesis: {
vars: {
in: { type:spectrum, flags:["src"], doc:"Spectrum input." },
out: { type:audio, doc:"Audio output." }
}
}
spec_dist: {
vars: {
in: { type:spectrum, flags:["src"], doc:"Spectrum input." },
bypass: { type:bool, value: false, doc:"Copy input to output without transform."},
ceiling: { type:coeff, value: 30.0, doc:"Ceiling parameter."},
expo: { type:coeff, value: 2.0, doc:"Exponent parameter."},
thresh: { type:coeff, value: 54.0, doc:"Threshold parameter."},
upr: { type:coeff, value: -0.7, doc:"Upper slope parameter."},
lwr: { type:coeff, value: 2.0, doc:"Lower slope parameter."},
mix: { type:coeff, value: 0.0, doc:"Basic/Bump Mix parameter."},
out: { type:spectrum, doc:"Spectrum output." },
}
presets: {
dry: {
}
kc: {
ceiling: 20.0,
expo: 2.0,
thresh: 65.0,
upr: 0.0,
lwr: 2.0,
mix: 0.0
}
a: {
ceiling: 20.0
expo: 2.0
thresh: 60.0
upr: [ -1.1, -0.99],
lwr: 2.0
mix: 0.0
}
b: {
ceiling: 20.0
expo: 2.0
thresh: [ 77.0, 74.0 ],
upr: -0.5
lwr: [ 3.0, 2.0 ],
mix: 0.0
}
c: {
ceiling: 20.0
expo: 2.0
thresh: 80.0
upr: -0.5
lwr: 5.0
mix: 0.0
}
d: {
ceiling: 20.0
expo: 2.0
thresh: 70.0
upr: [ -3.9, 04.5]
lwr: 4.0
mix: 0.0
}
f_1: {
ceiling: 20.0
expo: 2.0
thresh: 50.0
upr: -3.0
lwr: 1.0
mix: 0.0
}
f_2: {
ceiling: 20.0
expo: 2.0
thresh: 60.0
upr: -3.0
lwr: 1.0
mix: 0.0
}
f_3: {
ceiling: 20.0
expo: 2.0
thresh: 55.0
upr: -3.0
lwr: 1.0
mix: 0.0
}
f_4: {
ceiling: 20.0
expo: 2.0
thresh: 55.0
upr: -5.0
lwr: 1.0
mix: 0.0
}
g: {
ceiling: 40.0
expo: 8.0
thresh: [60.0 64.0]
upr: -0.7
lwr: 8.0
mix: 1.0
}
g_a: {
ceiling: 40.0
expo: 2.0
thresh: [50.0 54.0]
upr: -0.7
lwr: 2.0
mix: 1.0
}
g_1_a: {
ceiling: 20.0
expo: 2.0
thresh: [50.0 54.0]
upr: -0.7
lwr: 8.0
mix: 1.0
}
g_1_d: {
ceiling: [60.0 64.0]
expo: [ 7.0 5.0]
thresh: [40.0 34.0]
upr: [-0.4 -0.3]
lwr: [ 7.0 5.0]
mix: 1.0
}
}
}
compressor: {
vars: {
in: { type:audio, flags:["src"] true, doc:"Audio input." },
bypass: { type:bool, value: false, doc:"Bypass the compressor."},
igain: { type:coeff, value: 1.0, doc:"Input gain."},
thresh: { type:coeff, value: 90.0, doc:"Attack threshold in dB."},
ratio: { type:coeff, value: 2.0, doc:"Compression ratio."},
atk_ms: { type:coeff, value: 20.0, doc:"Attack time in milliseconds."},
rls_ms: { type:coeff, value: 20.0, doc:"Release time in milliseconds."},
wnd_ms: { type:coeff, value: 200.0, doc:"RMS calc. window length in milliseconds."},
maxWnd_ms: { type:coeff, value: 1000.0, doc:"Maximim (allocated) window length in milliseconds."},
ogain: { type:coeff, value: 1.0, doc:"Output gain."},
out: { type:audio, doc:"Audio output." },
}
presets: {
dflt: {
igain: 3.0
thresh: 60.0
ratio: 5.0
atk_ms: 5.0
rls_ms: 20.0
wnd_ms:100.0
ogain: 1.0
}
kc: {
bypass: false
igain: 3.0
thresh: 80.0
ratio: 2.0
atk_ms: 20.0
rls_ms: 1000.0
wnd_ms: 200.0
ogain: 1.0
}
input: {
bypass: false
igain: 2.0
thresh: 30.0
ratio: 12.0
atk_ms: 5.0
rls_ms: 20.0
wnd_ms: 20.0
ogain: 0.5
}
dry: {
}
a: {
igain: 6.0
ogain: 1.0
}
b: {
igain: 10.0
ogain: 1.0
}
c: {
igain: 11.0
ogain: 1.0
}
d: {
igain: 9.0
ogain: 1.0
}
f_1: {
igain: 6.0
ogain: 1.0
}
f_2: {
igain: 6.0
ogain: 1.0
}
f_3: {
igain: 6.0
ogain: 1.0
}
f_4: {
igain: 6.0
ogain: 1.0
}
g: {
igain: 10.0
ogain: 0.75
}
g_a: {
igain: 10.0
ogain: 0.75
}
g_1_a: {
igain: 10.0
ogain: 0.75
}
g_1_d: {
igain: 10.0
ogain: 0.75
}
}
}
limiter: {
vars: {
in: { type:audio, flags:["src"] true, doc:"Audio input." },
bypass: { type:bool, value: false, doc:"Bypass the limiter."},
igain: { type:coeff, value: 1.0, doc:"Input gain."},
thresh: { type:coeff, value: 0.0, doc:"Linear (0.0-1.0) threshold."},
ogain: { type:coeff, value: 1.0, doc:"Output gain."},
out: { type:audio, doc:"Audio output." },
}
presets: {
dflt: {
bypass: false,
igain: 1.0
thresh: 0.9,
ogain: 1.0
}
}
}
dc_filter: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
bypass: { type:bool, value: false, doc:"Bypass the DC filter."},
gain: { type:coeff, value: 1.0, doc:"Output gain."},
out: { type:audio, doc:"Audio output." },
}
presets: {
dflt: {
bypass: false,
gain: 1.0
}
}
}
audio_meter: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input." },
dbFl: { type:bool, value: true, doc:"Output in Decibels." },
wndMs: { type:ftime, value: 100.0, doc:"RMS window length." },
peakDb: { type:coeff, value: -10.0, doc:"Peak threshold." },
out: { type:coeff, value: 0.0, doc:"Meter output." },
peakFl: { type:bool, value: false, doc:"Peak output." }
clipFl: { type:bool, value: false, doc:"Clip indicator output."}
}
}
subnet: {
vars: {
}
}
poly: {
vars: {
count: { type:uint, doc:"Count of network duplicates." },
order: { type:string, value:"net", doc:"Execution order 'net'=net first 'proc'=proc first" }
}
}
sample_hold: {
vars: {
in: { type:audio, flags:["src"], doc:"Audio input source." },
period_ms: { type:ftime, value:50, doc:"Sample period in milliseconds." },
out: { type:sample, value:0.0, doc:"First value in the sample period." },
mean: { type:sample, value:0.0, doc:"Mean value of samples in period." },
}
}
number: {
vars: {
value: { type:numeric, value:0.0, doc:"Input and output value."},
store: { type:numeric, value:0.0, doc:"Store but don't emit until the next exec."}
}
}
timer: {
vars: {
srate: { type:srate, value:0, flags["src"], doc:"Sample rate to use as the time base. 0=Use default system sample rate." },
period_ms: { type:ftime, value:100, doc:"Timer period in milliseconds." },
out: { type:bool, value:false, doc:"Output pulse." },
}
}
counter: {
vars: {
trigger: { type:bool, flags["src"], doc:"Counter increments with each toggle of trigger." },
reset: { type:bool, value:false, doc:"Reset the counter to the initial value." },
init: { type:numeric, value:0.0, doc:"Counter initial value." },
min: { type:numeric, value:0.0, doc:"Minimum output value." },
max: { type:numeric, value:10.0, doc:"Maximum output value." },
inc: { type:numeric, value:1.0, doc:"Incrment value." },
repeat_fl: { type:bool, value:true, doc:"Repeat on reaching the limits." },
mode: { type:string, value:"modulo", doc:"limit mode: 'modulo'=wrap, 'reverse'=count in opposite direction, 'clip'=repeat limit value."},
out_type: { type:string, value:double, flags["init"], doc:"The type of the output value." },
out: { type:runtime, value:0.0, doc:"Counter output value."},
}
}
// All elements of the list must belong to the same of three possible types:
// string,cfg,numeric (uint,int,float,double)
list: {
vars: {
in: { type:uint, flags:["src"], doc:"List selection index." },
list: { type:cfg, doc:"List as a 'cfg' object." },
out: { type:runtime, doc:"List output value." },
value:{ type:runtime, flags["mult"], doc:"List 'mult' output per list value." },
}
}
add: {
vars: {
in: { type:numeric, flags:["src","mult"], doc:"Operands" },
otype: { type:string, value:double, flags:["init"], doc:"The type of the output value." },
out: { type:runtime, flags:["no_src"], doc:"Result" },
}
}
preset: {
vars: {
in: { type:string, flags:["src"], doc:"Preset to select." },
}
}
xfade_ctl: {
poly_limit_cnt: 1,
// Notes:
// 1. It would be better to setup the source net-proc as a 'in' variable with type 'net'.
// 2. The only purpose for the 'srateSrc' is to get the sample rate of the system.
vars: {
net: { type:string, doc:"Proc name of the poly network."},
netSfxId: { type:uint, value: 0, doc:"Label sfx id of the source poly instance."},
srateSrc: { type:audio, flags:["src"], doc:"Audio source to derive the sample rate."},
durMs: { type:uint, value:1000, doc:"Cross-fade duration in milliseconds" },
trigger: { type:all, doc:"Start cross-fade." },
preset: { type:string, doc:"Preset to apply to the poly network." },
gain: { type:coeff, flags:["mult"], value:0, doc:"Cross-fade gain output." }
}
},
poly_merge: {
vars: {
in: { type:audio, flags:["src", "mult"], doc:"Audio input channel." },
gain: { type:coeff, value: 0, flags:["src", "mult"], doc:"Input channel gain." },
out_gain: { type:coeff, value: 1, doc:"Output gain" },
out: { type:audio, doc:"Audio output." },
}
},
print: {
vars: {
in: { type:all, flags:["mult"], doc: "Value to print." },
eol_fl: { type:all, doc: "Trigger an end-of-line." },
text: { type:cfg, doc: "List of labels." },
}
}
}

34
examples/subnet_dict.cfg Normal file
View File

@ -0,0 +1,34 @@
{
mod_osc: {
vars: {
hz: { proxy:hz_lfo.dc, doc:"Audio frequency" },
hz_mod_hz: { proxy:hz_lfo.hz, doc:"Frequency modulator hz" },
hz_mod_depth: { proxy:hz_lfo.gain, doc:"Frequency modulator depth" },
amp_mod_hz: { proxy:amp_lfo.hz, doc:"Amplitude modulator hz" },
amp_mod_depth: { proxy:amp_lfo.gain, doc:"Amplutide modulator depth."},
mo_out: { proxy:ogain.out flags:[out] doc:"Oscillator output."},
},
network: {
procs: {
hz_lfo: { class: sine_tone, args: { chCnt:1 }}
hz_sh: { class: sample_hold, in:{ in:hz_lfo.out }}
amp_lfo: { class: sine_tone, args: { chCnt:1 }}
amp_sh: { class: sample_hold, in:{ in:amp_lfo.out }}
osc: { class: sine_tone, in:{ hz: hz_sh.out }}
ogain: { class: audio_gain, in:{ in:osc.out, gain:amp_sh.out}}
}
presets: {
net_a: { hz_lfo: { dc:220, gain:55 }, amp_lfo: { gain:0.8 } },
net_b: { hz_lfo: { dc:110, gain:25 }, amp_lfo: { gain:0.7 } },
}
}
}
}

View File

@ -1,13 +1,12 @@
{ {
param: 5,
libcw: {
io: { io: {
callbackMutexTimeOutMs: 100, callbackMutexTimeOutMs: 100,
} }
ui: { ui: {
enableFl: true,
asyncFl: false,
physRootDir: "~/src/cw_io_template/src/proj/html", physRootDir: "~/src/cw_io_template/src/proj/html",
dfltPageFn: "index.html", dfltPageFn: "index.html",
port: 5687, port: 5687,
@ -17,10 +16,10 @@
websockTimeOutMs: 50, // max time out while blocking for a websock event websockTimeOutMs: 50, // max time out while blocking for a websock event
idleMsgPeriodMs: 50, // period without messages before an idle message is generated idleMsgPeriodMs: 50, // period without messages before an idle message is generated
uiCfgFn: "ui.cfg", // default UI resource description uiCfgFn: "ui.cfg", // default UI resource description
asyncFl: false
}, },
serial: { serial: {
enableFl: false,
pollPeriodMs: 50, pollPeriodMs: 50,
recvBufByteN: 512, recvBufByteN: 512,
@ -39,6 +38,7 @@
}, },
midi: { midi: {
enableFl: false,
parseBufByteCnt: 1024, parseBufByteCnt: 1024,
appNameStr: "cwtest", appNameStr: "cwtest",
fileDevName: "file_dev", fileDevName: "file_dev",
@ -50,13 +50,15 @@
{ "label":"file_0", { "label":"file_0",
//"file": "/home/kevin/src/cwtest/src/cwtest/cfg/gutim_full/data1/beck1/record_4/midi.mid", //"file": "/home/kevin/src/cwtest/src/cwtest/cfg/gutim_full/data1/beck1/record_4/midi.mid",
"enable_fl": false }, "enableFl": false },
] ]
asyncFl: true, asyncFl: true,
}, },
audio: { audio: {
enableFl: false,
meterMs: 50, // audio meter filter length and meter callback period meterMs: 50, // audio meter filter length and meter callback period
threadTimeOutMs: 50, // audio thread cond var time out threadTimeOutMs: 50, // audio thread cond var time out
@ -92,6 +94,7 @@
}, },
socket: { socket: {
enableFl: false,
asyncFl: false, asyncFl: false,
maxSocketCnt: 10, maxSocketCnt: 10,
recvBufByteCnt: 4096, recvBufByteCnt: 4096,
@ -100,5 +103,3 @@
} }
} }
}

28
src/caw/main.cfg Normal file
View File

@ -0,0 +1,28 @@
{
param: 5,
base_dir: "~/src/caw/examples",
proc_dict: "~/src/caw/examples/proc_dict.cfg",
subnet_dict: "~/src/caw/examples/subnet_dict.cfg",
mode: non_real_time,
programs: {
example_01: {
durLimitSecs:5.0,
network: {
procs: {
osc: { class: sine_tone },
af: { class: audio_file_out, in: { in:osc.out } args:{ fname:"$/out.wav"} }
}
}
}
}
}

432
src/caw/main.cpp Normal file
View File

@ -0,0 +1,432 @@
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwTest.h"
#include "cwMem.h"
#include "cwText.h"
#include "cwObject.h"
#include "cwFileSys.h"
#include "cwTime.h"
#include "cwMidiDecls.h"
#include "cwFlowDecl.h"
#include "cwFlow.h"
#include "cwIo.h"
using namespace cw;
rc_t test( const object_t* cfg, int argc, char* argv[] );
typedef struct app_str
{
object_t* cfg; // complete cfg.
bool real_time_fl; // Execute in non-real-time mode
const char* pgm_label; //
const object_t* pgm_cfg; //
const char* base_dir; //
char* proj_dir; // Project directory <base_dir>/<pgm_label>
object_t* io_cfg; // IO lib cfg.
object_t* proc_class_dict_cfg; //
object_t* subnet_dict_cfg;
unsigned value;
io::handle_t ioH;
} app_t;
enum
{
kPanelDivId,
kQuitBtnId,
kIoReportBtnId,
kNetPrintBtnId,
kReportBtnId,
kLatencyBtnId,
kValueNumbId
};
ui::appIdMap_t appIdMapA[] = {
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
{ kPanelDivId, kIoReportBtnId, "ioReportBtnId" },
{ kPanelDivId, kNetPrintBtnId, "netPrintBtnId" },
{ kPanelDivId, kReportBtnId, "reportBtnId" },
{ kPanelDivId, kLatencyBtnId, "latencyBtnId" },
{ kPanelDivId, kValueNumbId, "valueNumbId" }
};
const unsigned appIdMapN = sizeof(appIdMapA)/sizeof(appIdMapA[0]);
void print( void* arg, const char* text )
{
printf("%s\n",text);
}
rc_t _ui_value_callback(app_t* app, const io::ui_msg_t& m )
{
switch( m.appId )
{
case kQuitBtnId:
io::stop( app->ioH );
break;
case kIoReportBtnId:
io::report(app->ioH);
break;
case kNetPrintBtnId:
break;
case kReportBtnId:
break;
case kLatencyBtnId:
latency_measure_report(app->ioH);
latency_measure_setup(app->ioH);
break;
case kValueNumbId:
app->value = m.value->u.u;
cwLogInfo("Setting value:%i",app->value);
break;
}
return kOkRC;
}
rc_t _ui_echo_callback(app_t* app, const io::ui_msg_t& m )
{
switch( m.appId )
{
case kValueNumbId:
{
uiSendValue( app->ioH, io::uiFindElementUuId( app->ioH, kValueNumbId ), app->value );
}
break;
}
return kOkRC;
}
rc_t _ui_callback( app_t* app, const io::ui_msg_t& m )
{
rc_t rc = kOkRC;
switch( m.opId )
{
case ui::kConnectOpId:
cwLogInfo("UI Connected: wsSessId:%i.",m.wsSessId);
break;
case ui::kDisconnectOpId:
cwLogInfo("UI Disconnected: wsSessId:%i.",m.wsSessId);
break;
case ui::kInitOpId:
cwLogInfo("UI Init.");
break;
case ui::kValueOpId:
_ui_value_callback( app, m );
break;
case ui::kCorruptOpId:
cwLogInfo("UI Corrupt.");
break;
case ui::kClickOpId:
cwLogInfo("UI Click.");
break;
case ui::kSelectOpId:
cwLogInfo("UI Select.");
break;
case ui::kEchoOpId:
_ui_echo_callback( app, m );
break;
case ui::kIdleOpId:
break;
case ui::kInvalidOpId:
// fall through
default:
assert(0);
break;
}
return rc;
}
rc_t _io_callback( void* arg, const io::msg_t* m )
{
app_t* app = (app_t*)arg;
switch( m->tid )
{
case io::kThreadTId:
break;
case io::kTimerTId:
break;
case io::kSerialTId:
break;
case io::kMidiTId:
break;
case io::kAudioTId:
break;
case io::kAudioMeterTId:
break;
case io::kSockTId:
break;
case io::kWebSockTId:
break;
case io::kUiTId:
_ui_callback(app,m->u.ui);
break;
case io::kExecTId:
break;
default:
assert(0);
}
return kOkRC;
}
rc_t _parse_cfg( app_t& app, int argc, char* argv[] )
{
rc_t rc = kOkRC;
const char* io_cfg_fn = nullptr;
const char* mode_label = nullptr;
const object_t* pgmL = nullptr;
const char* proc_cfg_fname = nullptr;
const char* subnet_cfg_fname = nullptr;
if( argc < 3 )
{
cwLogPrint("Usage: caw <cfg_fname> <pgm_label>");
rc = kInvalidArgRC;
goto errLabel;
}
else
{
// parse the cfg. file
if((rc = objectFromFile(argv[1],app.cfg)) != kOkRC )
{
rc = cwLogError(rc,"Parsing failed on the cfg. file '%s'.",argv[1]);
goto errLabel;
}
// parse the cfg parameters
if((rc = app.cfg->readv("param", 0, app.value,
"io_cfg", kOptFl, io_cfg_fn,
"base_dir", 0, app.base_dir,
"proc_dict",0,proc_cfg_fname,
"subnet_dict",0,subnet_cfg_fname,
"mode", 0, mode_label,
"programs", kDictTId, pgmL)) != kOkRC )
{
rc = cwLogError(rc,"'caw' system parameter processing failed.");
goto errLabel;
}
// set the real-time mode flag
app.real_time_fl = !textIsEqual(mode_label,"non_real_time");
// if we are in real-time mode then the io_cfg file must be given
if( app.real_time_fl && io_cfg_fn == nullptr )
{
rc = cwLogError(kSyntaxErrorRC,"To operation in real-time mode an 'io_cfg' file must be provided.");
goto errLabel;
}
// parse the 'io_cfg' file
if( app.real_time_fl )
if((rc = objectFromFile(io_cfg_fn,app.io_cfg)) != kOkRC )
{
rc = cwLogError(rc,"'caw' IO cfg. file parsing failed on '%s'.",cwStringNullGuard(io_cfg_fn));
goto errLabel;
}
// parse the proc dict. file
if((rc = objectFromFile(proc_cfg_fname,app.proc_class_dict_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,app.subnet_dict_cfg)) != kOkRC )
{
rc = cwLogError(rc,"The flow subnet dictionary could not be read from '%s'.",cwStringNullGuard(subnet_cfg_fname));
goto errLabel;
}
// get the pgm label
if( textLength(argv[2]) == 0 )
{
rc = cwLogError(kSyntaxErrorRC,"No 'caw' program label was given.");
goto errLabel;
}
app.pgm_label = argv[2];
// find the parameters for the requested program
for(unsigned i=0; i<pgmL->child_count(); i++)
{
const object_t* pgm = pgmL->child_ele(i);
if( textIsEqual( pgm->pair_label(), app.pgm_label ) )
{
if( pgm->pair_value() == nullptr || !pgm->pair_value()->is_dict() )
{
rc = cwLogError(kSyntaxErrorRC,"The parameters for the program '%s' is not a dictionary.",cwStringNullGuard(app.pgm_label));
goto errLabel;
}
app.pgm_cfg = pgm->pair_value();
break;
}
}
if( app.pgm_cfg == nullptr )
rc =cwLogError(kEleNotFoundRC,"The program '%s' was not found in the cfg. program list.",cwStringNullGuard(app.pgm_label));
else
{
if((app.proj_dir = filesys::makeFn(app.base_dir,nullptr,nullptr,app.pgm_label,nullptr)) == nullptr )
{
rc = cwLogError(kOpFailRC,"An error occurred while forming the the project directory name for '%s' / '%s'.",cwStringNullGuard(app.base_dir),cwStringNullGuard(app.pgm_label));
goto errLabel;
}
if( !filesys::isDir(app.proj_dir))
{
if((rc = filesys::makeDir(app.proj_dir)) != kOkRC )
{
rc = cwLogError(kOpFailRC,"Project directory create failed.");
goto errLabel;
}
}
}
}
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"App. cfg. parse failed.");
return rc;
}
rc_t _main_gui( app_t& app )
{
rc_t rc = kOkRC;
if((rc = create( app.ioH, app.io_cfg, _io_callback, &app, appIdMapA, appIdMapN ) ) != kOkRC )
{
rc = cwLogError(rc,"IO create failed.");
goto errLabel;
}
// start the IO framework instance
if((rc = io::start(app.ioH)) != kOkRC )
{
rc = cwLogError(rc,"Preset-select app start failed.");
goto errLabel;
}
// execute the io framework
while( !io::isShuttingDown(app.ioH))
{
// This call will block on the websocket handle
// for up to io_cfg->ui.websockTimeOutMs milliseconds
io::exec(app.ioH,50);
}
// stop the io framework
if((rc = io::stop(app.ioH)) != kOkRC )
{
rc = cwLogError(rc,"IO API stop failed.");
goto errLabel;
}
errLabel:
return rc;
}
int main( int argc, char* argv[] )
{
rc_t rc = kOkRC;
app_t app = {};
flow::handle_t flowH;
cw::log::createGlobal();
cwLogInfo("caw: args:%i", argc);
if((rc = _parse_cfg(app,argc,argv)) != kOkRC )
goto errLabel;
// create the flow object
if((rc = create( flowH,
app.proc_class_dict_cfg,
app.pgm_cfg,
app.subnet_dict_cfg,
app.proj_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;
}
destroy(app.ioH);
mem::release(app.proj_dir);
if( app.proc_class_dict_cfg != nullptr )
app.proc_class_dict_cfg->free();
if( app.subnet_dict_cfg != nullptr )
app.subnet_dict_cfg->free();
if( app.io_cfg != nullptr )
app.io_cfg->free();
if( app.cfg != nullptr )
app.cfg->free();
cw::log::destroyGlobal();
return 0;
}

View File

@ -1,276 +0,0 @@
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwText.h"
#include "cwObject.h"
#include "cwIo.h"
using namespace cw;
typedef struct app_str
{
object_t* cfg;
unsigned value;
const object_t* io_cfg;
io::handle_t ioH;
} app_t;
enum
{
kPanelDivId,
kQuitBtnId,
kIoReportBtnId,
kNetPrintBtnId,
kReportBtnId,
kLatencyBtnId,
kValueNumbId
};
ui::appIdMap_t appIdMapA[] = {
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
{ kPanelDivId, kIoReportBtnId, "ioReportBtnId" },
{ kPanelDivId, kNetPrintBtnId, "netPrintBtnId" },
{ kPanelDivId, kReportBtnId, "reportBtnId" },
{ kPanelDivId, kLatencyBtnId, "latencyBtnId" },
{ kPanelDivId, kValueNumbId, "valueNumbId" }
};
const unsigned appIdMapN = sizeof(appIdMapA)/sizeof(appIdMapA[0]);
void print( void* arg, const char* text )
{
printf("%s\n",text);
}
rc_t _ui_value_callback(app_t* app, const io::ui_msg_t& m )
{
switch( m.appId )
{
case kQuitBtnId:
io::stop( app->ioH );
break;
case kIoReportBtnId:
io::report(app->ioH);
break;
case kNetPrintBtnId:
break;
case kReportBtnId:
break;
case kLatencyBtnId:
latency_measure_report(app->ioH);
latency_measure_setup(app->ioH);
break;
case kValueNumbId:
app->value = m.value->u.u;
cwLogInfo("Setting value:%i",app->value);
break;
}
return kOkRC;
}
rc_t _ui_echo_callback(app_t* app, const io::ui_msg_t& m )
{
switch( m.appId )
{
case kValueNumbId:
{
uiSendValue( app->ioH, io::uiFindElementUuId( app->ioH, kValueNumbId ), app->value );
}
break;
}
return kOkRC;
}
rc_t _ui_callback( app_t* app, const io::ui_msg_t& m )
{
rc_t rc = kOkRC;
switch( m.opId )
{
case ui::kConnectOpId:
cwLogInfo("UI Connected: wsSessId:%i.",m.wsSessId);
break;
case ui::kDisconnectOpId:
cwLogInfo("UI Disconnected: wsSessId:%i.",m.wsSessId);
break;
case ui::kInitOpId:
cwLogInfo("UI Init.");
break;
case ui::kValueOpId:
_ui_value_callback( app, m );
break;
case ui::kCorruptOpId:
cwLogInfo("UI Corrupt.");
break;
case ui::kClickOpId:
cwLogInfo("UI Click.");
break;
case ui::kSelectOpId:
cwLogInfo("UI Select.");
break;
case ui::kEchoOpId:
_ui_echo_callback( app, m );
break;
case ui::kIdleOpId:
break;
case ui::kInvalidOpId:
// fall through
default:
assert(0);
break;
}
return rc;
}
rc_t _io_callback( void* arg, const io::msg_t* m )
{
app_t* app = (app_t*)arg;
switch( m->tid )
{
case io::kThreadTId:
break;
case io::kTimerTId:
break;
case io::kSerialTId:
break;
case io::kMidiTId:
break;
case io::kAudioTId:
break;
case io::kAudioMeterTId:
break;
case io::kSockTId:
break;
case io::kWebSockTId:
break;
case io::kUiTId:
_ui_callback(app,m->u.ui);
break;
case io::kExecTId:
break;
default:
assert(0);
}
return kOkRC;
}
rc_t _parse_cfg( app_t& app, int argc, char* argv[] )
{
rc_t rc = kOkRC;
if( argc < 2 || textLength(argv[1])==0 )
{
rc = cwLogError(kInvalidArgRC,"No cfg. file was given.");
goto errLabel;
}
else
{
if((rc = objectFromFile(argv[1],app.cfg)) != kOkRC )
{
rc = cwLogError(rc,"The file '%s'.",argv[1]);
goto errLabel;
}
if((rc = app.cfg->getv("param", app.value,
"libcw", app.io_cfg)) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"The 'param' cfg. field was not found.");
goto errLabel;
}
}
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"App. cfg. parse failed.");
return rc;
}
int main( int argc, char* argv[] )
{
rc_t rc = kOkRC;
app_t app = {};
cw::log::createGlobal();
cwLogInfo("Project template: args:%i", argc);
if((rc = _parse_cfg(app,argc,argv)) != kOkRC )
goto errLabel;
if((rc = create( app.ioH, app.io_cfg, _io_callback, &app, appIdMapA, appIdMapN ) ) != kOkRC )
{
rc = cwLogError(rc,"IO create failed.");
goto errLabel;
}
// start the IO framework instance
if((rc = io::start(app.ioH)) != kOkRC )
{
rc = cwLogError(rc,"Preset-select app start failed.");
goto errLabel;
}
//io::uiReport(app.ioH);
// execute the io framework
while( !io::isShuttingDown(app.ioH))
{
// This call will block on the websocket handle
// for up to io_cfg->ui.websockTimeOutMs milliseconds
io::exec(app.ioH);
}
// stop the io framework
if((rc = io::stop(app.ioH)) != kOkRC )
{
rc = cwLogError(rc,"IO API stop failed.");
goto errLabel;
}
errLabel:
destroy(app.ioH);
if( app.cfg != nullptr )
app.cfg->free();
cw::log::destroyGlobal();
return 0;
}