Browse Source

cmRtSys.h/c and cmRtSysMsg.h: Replacement for cmAudioSys.h/c. Initial Commit.

cmUiRtSysMstr.h/c: Renamed from cmUiAudioSys.h/c.
master
kevin 11 years ago
parent
commit
7ce3d9b72a
6 changed files with 2432 additions and 2 deletions
  1. 5
    2
      Makefile.am
  2. 1465
    0
      cmRtSys.c
  3. 314
    0
      cmRtSys.h
  4. 99
    0
      cmRtSysMsg.h
  5. 509
    0
      cmUiRtSysMstr.c
  6. 40
    0
      cmUiRtSysMstr.h

+ 5
- 2
Makefile.am View File

@@ -30,8 +30,11 @@ cmSRC += src/libcm/cmMidiFilePlay.c src/libcm/cmMidiPort.c src/libcm/cmMidiFile.
30 30
 cmHDR += src/libcm/cmAudioFile.h src/libcm/cmAudioFileMgr.h src/libcm/cmMsgProtocol.h src/libcm/cmAudioSys.h src/libcm/cmAudioPortFile.h src/libcm/cmAudioFileDev.h 
31 31
 cmSRC += src/libcm/cmAudioFile.c src/libcm/cmAudioFileMgr.c src/libcm/cmMsgProtocol.c src/libcm/cmAudioSys.c src/libcm/cmAudioPortFile.c src/libcm/cmAudioFileDev.c
32 32
 
33
-cmHDR += src/libcm/cmDevCfg.h src/libcm/cmUi.h src/libcm/cmUiDrvr.h src/libcm/cmUiAudioSysMstr.h
34
-cmSRC += src/libcm/cmDevCfg.c src/libcm/cmUi.c src/libcm/cmUiDrvr.c src/libcm/cmUiAudioSysMstr.c
33
+cmHDR += src/libcm/cmRtSys.h src/libcm/cmUiRtSysMstr.h src/libcm/cmRtSysMsg.h 
34
+cmHDR += src/libcm/cmRtSys.c src/libcm/cmUiRtSysMstr.c
35
+
36
+cmHDR += src/libcm/cmDevCfg.h src/libcm/cmUi.h src/libcm/cmUiDrvr.h 
37
+cmSRC += src/libcm/cmDevCfg.c src/libcm/cmUi.c src/libcm/cmUiDrvr.c
35 38
 
36 39
 cmHDR += src/libcm/cmFrameFile.h src/libcm/cmFeatFile.h src/libcm/cmCsv.h src/libcm/cmAudLabelFile.h src/libcm/cmTagFile.h
37 40
 cmSRC += src/libcm/cmFrameFile.c src/libcm/cmFeatFile.c src/libcm/cmCsv.c src/libcm/cmAudLabelFile.c src/libcm/cmTagFile.c

+ 1465
- 0
cmRtSys.c
File diff suppressed because it is too large
View File


+ 314
- 0
cmRtSys.h View File

@@ -0,0 +1,314 @@
1
+// cmRtSys.h
2
+// Implements a real-time audio processing engine.
3
+//
4
+// The audio system is composed a collection of independent sub-systems.
5
+// Each sub-system maintains a thread which runs asynchrounsly
6
+// from the application, the MIDI devices, and the audio devices.
7
+// To faciliate communication between these components each sub-system maintains 
8
+// two thread-safe data buffers one for control information and a second 
9
+// for audio data.
10
+//
11
+// The audio devices are the primary driver for the system. 
12
+// Callbacks from the audio devices (See #cmApCallbackPtr_t) 
13
+// inserts incoming audio samples into the audio
14
+// record buffers and extracts samples from the playback buffer.  
15
+// When sufficient incoming samples and outgoing empty buffer space exists
16
+// a sub-system thread is waken up by the callback. This triggers a DSP audio 
17
+// processing cycle which empties/fills the audio buffers. During a DSP
18
+// processing cycle control messages from the application and MIDI are blocked and
19
+// buffered. Upon completetion of the DSP cycle a control message
20
+// transfer cycles occurs - buffered incoming messages are passed to 
21
+// the DSP system and messages originating in the DSP system are
22
+// buffered by the audio system for later pickup by the application
23
+// or MIDI system.
24
+// 
25
+// Note that control messages that arrive when the DSP cycle is not
26
+// occurring can pass directly through to the DSP system.
27
+//
28
+// The DSP system sends messages back to the host by calling
29
+// cmRtDspToHostFunc_t provided by cmRtSysCtx_t. These
30
+// calls are always made from within an audio system call to 
31
+// audio or control update within cmRtCallback_t. cmRtDspToHostFunc_t
32
+// simply stores the message in a message buffer.  The host picks
33
+// up the message at some later time when it notices that messages
34
+// are waiting via polling cmRtSysIsMsgWaiting().
35
+//
36
+// Implementation: \n
37
+// The audio sub-systems work by maintaining an internal thread
38
+// which blocks on a mutex condition variable.
39
+// While the thread is blocked the mutex is unlocked allowing messages
40
+// to pass directly through to the DSP procedure via cmRtCallback().
41
+//
42
+// Periodic calls from running audio devices update the audio buffer. 
43
+// When the audio buffer has input samples waiting and output space
44
+// available the condition variable is signaled, the mutex is 
45
+// then automatically locked by the system, and the DSP execution
46
+// procedure is called via cmRtCallback().
47
+//
48
+// Messages arriving while the mutex is locked are queued and
49
+// delivered to the DSP procedure at the end of the DSP execution
50
+// procedure.
51
+//
52
+// Usage example and testing code:
53
+// See  cmRtSysTest().
54
+// \snippet cmRtSys.c cmRtSysTest
55
+
56
+#ifndef cmRtSys_h
57
+#define cmRtSys_h
58
+
59
+#ifdef __cplusplus
60
+extern "C" {
61
+#endif
62
+
63
+  // Audio system result codes
64
+  enum
65
+  {
66
+    kOkRtRC = cmOkRC,
67
+    kThreadErrRtRC,
68
+    kMutexErrRtRC,
69
+    kTsQueueErrRtRC,
70
+    kMsgEnqueueFailRtRC,
71
+    kAudioDevSetupErrRtRC,
72
+    kAudioBufSetupErrRtRC,
73
+    kAudioDevStartFailRtRC,
74
+    kAudioDevStopFailRtRC,
75
+    kBufTooSmallRtRC,
76
+    kNoMsgWaitingRtRC,
77
+    kMidiSysFailRtRC,
78
+    kMsgSerializeFailRtRC,
79
+    kStateBufFailRtRC,
80
+    kInvalidArgRtRC,
81
+    kNotInitRtRC,
82
+    kTimeOutErrRtRC
83
+  };
84
+
85
+  enum
86
+  {
87
+    kAsDfltMsgQueueByteCnt   = 0xffff,
88
+    kAsDfltDevFramesPerCycle = 512,
89
+    kAsDfltDspFramesPerCycle = 64,
90
+    kAsDfltBufCnt            = 3,
91
+    kAsDfltSrate             = 44100,
92
+    kAsDfltSyncToInputFl     = 1,
93
+    kAsDfltMinMeterMs        = 10,
94
+    kAsDfltMeterMs           = 50,
95
+    kAsDfltMaxMeterMs        = 1000
96
+  };
97
+
98
+  typedef cmHandle_t cmRtSysH_t;  //< Audio system handle type
99
+  typedef unsigned   cmRtRC_t;       //< Audio system result code
100
+
101
+  struct cmRtSysCtx_str;
102
+
103
+  //
104
+  // DSP system callback function.
105
+  //
106
+  // This is the sole point of entry into the DSP system while the audio system is running.
107
+  //
108
+  // ctxPtr is pointer to a cmRtSysCtx_t record.
109
+  //
110
+  // This function is called under two circumstances:
111
+  //
112
+  // 1) To notify the DSP system that the audio input/output buffers need to be serviced.
113
+  // This is a perioidic request which the DSP system uses as its execution trigger.
114
+  // cmRtSysCtx_t.audioRateFl is set to true to indicate this type of callback.
115
+  //
116
+  // 2) To pass messages from the host application to the DSP system.
117
+  // The DSP system is asyncronous with the host because it executes in the 
118
+  // audio system thread rather than the host thread.  The cmRtSysDeliverMsg() 
119
+  // function synchronizes incoming messages with the internal audio system 
120
+  // thread to prevent thread collisions.
121
+  //
122
+  // Notes:
123
+  // This callback is always made with the internal audio system mutex locked.
124
+  //
125
+  // The signal time covered by the callback is from 
126
+  // ctx->begSmpIdx to ctx->begSmpIdx+cfg->dspFramesPerCycle.
127
+  //
128
+  // The return value is currently not used.
129
+  typedef cmRC_t (*cmRtCallback_t)(void* ctxPtr, unsigned msgByteCnt, const void* msgDataPtr );
130
+
131
+  
132
+  // Audio device sub-sytem configuration record 
133
+  typedef struct cmRtSysArgs_str
134
+  {
135
+    cmRpt_t*       rpt;               // system console object
136
+    unsigned       inDevIdx;          // input audio device
137
+    unsigned       outDevIdx;         // output audio device
138
+    bool           syncInputFl;       // true/false sync the DSP update callbacks with audio input/output
139
+    unsigned       msgQueueByteCnt;   // Size of the internal msg queue used to buffer msgs arriving via cmRtSysDeliverMsg().
140
+    unsigned       devFramesPerCycle; // (512) Audio device samples per channel per device update buffer.
141
+    unsigned       dspFramesPerCycle; // (64)  Audio samples per channel per DSP cycle.
142
+    unsigned       audioBufCnt;       // (3)   Audio device buffers.
143
+    double         srate;             // Audio sample rate.
144
+  } cmRtSysArgs_t;
145
+
146
+  // Audio sub-system configuration record.
147
+  // This record is provided by the host to configure the audio system
148
+  // via cmRtSystemAllocate() or cmRtSystemInitialize().
149
+  typedef struct cmRtSysSubSys_str
150
+  {
151
+    cmRtSysArgs_t    args;              // Audio device configuration
152
+    cmRtCallback_t   cbFunc;            // DSP system entry point function.
153
+    void*            cbDataPtr;         // Host provided data for the DSP system callback.   
154
+  } cmRtSysSubSys_t;
155
+
156
+
157
+  // Signature of a callback function provided by the audio system to receive messages 
158
+  // from the DSP system for later dispatch to the host application.
159
+  // This declaration is used by the DSP system implementation and the audio system.
160
+  // Note that this function is intended to convey one message broken into multiple parts.
161
+  // See cmTsQueueEnqueueSegMsg() for the equivalent interface.
162
+  typedef cmRtRC_t (*cmRtDspToHostFunc_t)(struct cmRtSysCtx_str* p, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
163
+
164
+  // Record passed with each call to the DSP callback function cmRtCallback_t
165
+  typedef struct cmRtSysCtx_str
166
+  {
167
+    void*               reserved;      // used internally by the audio system
168
+
169
+    bool                audioRateFl;   // true if this is an audio update callback
170
+
171
+    unsigned            srcNetNodeId;  // Source net node if this is a msg callback originating from a remote network node. 
172
+    unsigned            rtSubIdx;      // index of the sub-system this DSP process is serving
173
+
174
+    cmRtSysSubSys_t*    ss;            // ptr to a copy of the cfg recd used to initialize the audio system
175
+    unsigned            begSmpIdx;     // gives signal time as a sample count
176
+
177
+    cmRtDspToHostFunc_t dspToHostFunc; // Callback used by the DSP process to send messages to the host
178
+                                       // via the audio system. Returns a cmRtRC_t result code.
179
+
180
+                                       // output (playback) buffers
181
+    cmSample_t**        oChArray;      // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
182
+    unsigned            oChCnt;        // count of output channels (ele's in oChArray[])
183
+
184
+                                       // input (recording) buffers
185
+    cmSample_t**        iChArray;      // each ele is a ptr to buffer with cfg.dspFramesPerCycle samples
186
+    unsigned            iChCnt;        // count of input channels (ele's in iChArray[])
187
+    
188
+  } cmRtSysCtx_t;
189
+
190
+
191
+  // Audio system configuration record used by cmRtSysAllocate().
192
+  typedef struct cmRtSysCfg_str
193
+  {
194
+    cmRtSysSubSys_t*      ssArray;      // sub-system cfg record array
195
+    unsigned              ssCnt;        // count of sub-systems   
196
+    unsigned              meterMs;      // Meter sample period in milliseconds
197
+    void*                 clientCbData; // User arg. for clientCbFunc().
198
+    cmTsQueueCb_t         clientCbFunc; // Called by  cmRtSysReceiveMsg() to deliver internally generated msg's to the host. 
199
+                                        //  Set to NULL if msg's will be directly returned by buffers passed to cmRtSysReceiveMsg().
200
+    cmUdpNetH_t           netH;
201
+  } cmRtSysCfg_t;
202
+
203
+  extern cmRtSysH_t cmRtSysNullHandle;
204
+
205
+  // Allocate and initialize an audio system as a collection of 'cfgCnt' sub-systems.
206
+  // Prior to call this function the audio audio ports system must be initalized 
207
+  // (via cmApInitialize()) and the MIDI port system must be initialized 
208
+  // (via cmMpInitialize()).  Note also that cmApFinalize() and cmMpFinalize() 
209
+  // cannot be called prior to cmRtSysFree().
210
+  // See cmRtSystemTest() for a complete example.
211
+  cmRtRC_t  cmRtSysAllocate( cmRtSysH_t* hp, cmRpt_t* rpt, const cmRtSysCfg_t* cfg  );
212
+
213
+  // Finalize and release any resources held by the audio system.
214
+  cmRtRC_t  cmRtSysFree( cmRtSysH_t* hp );
215
+
216
+  // Returns true if 'h' is a handle which was successfully allocated by 
217
+  // cmRtSysAllocate().
218
+  bool      cmRtSysHandleIsValid( cmRtSysH_t h );
219
+
220
+  // Reinitialize a previously allocated audio system.  This function
221
+  // begins with a call to cmRtSysFinalize().   
222
+  // Use cmRtSysEnable(h,true) to begin processing audio following this call.
223
+  cmRtRC_t  cmRtSysInitialize( cmRtSysH_t h, const cmRtSysCfg_t* cfg );
224
+
225
+  // Complements cmRtSysInitialize(). In general there is no need to call this function
226
+  // since calls to cmRtSysInitialize() and cmRtSysFree() automaticatically call it.
227
+  cmRtRC_t  cmRtSysFinalize( cmRtSysH_t h );
228
+
229
+  // Returns true if the audio system has been successfully initialized.
230
+  bool     cmRtSysIsInitialized( cmRtSysH_t );
231
+
232
+  // Returns true if the audio system is enabled.
233
+  bool      cmRtSysIsEnabled( cmRtSysH_t h );
234
+
235
+  // Enable/disable the audio system.  Enabling the starts audio stream
236
+  // in/out of the system.
237
+  cmRtRC_t  cmRtSysEnable( cmRtSysH_t h, bool enableFl );
238
+
239
+  //
240
+  // DSP to Host delivery function
241
+  //
242
+
243
+  // This function is used to pass messages from a DSP process to the HOST it
244
+  // is always called from within the real-time thread.
245
+  cmRtRC_t cmRtSysDspToHostSegMsg( cmRtSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt);
246
+  cmRtRC_t cmRtSysDspToHost( cmRtSysH_t h, const void* msgDataPtr, unsigned msgByteCnt);
247
+
248
+
249
+  //
250
+  // Host to DSP delivery functions
251
+  // 
252
+
253
+  // Deliver a message from the host application to the DSP process. (host -> DSP);
254
+  // The message is formed as a concatenation of the bytes in each of the segments
255
+  // pointed to by 'msgDataPtrArrary[segCnt][msgByteCntArray[segCnt]'.
256
+  // This is the canonical msg delivery function in so far as the other host->DSP
257
+  // msg delivery function are written in terms of this function.
258
+  // The first 4 bytes in the first segment must contain the index of the audio sub-system
259
+  // which is to receive the message.
260
+  cmRtRC_t  cmRtSysDeliverSegMsg(  cmRtSysH_t h, const void* msgDataPtrArray[], unsigned msgByteCntArray[], unsigned msgSegCnt, unsigned srcNetNodeId );
261
+
262
+  // Deliver a single message from the host to the DSP system.
263
+  cmRtRC_t  cmRtSysDeliverMsg(   cmRtSysH_t h,  const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
264
+
265
+  // Deliver a single message from the host to the DSP system.
266
+  // Prior to delivery the 'id' is prepended to the message.
267
+  cmRtRC_t  cmRtSysDeliverIdMsg(  cmRtSysH_t h, unsigned rtSubIdx, unsigned id, const void* msgPtr, unsigned msgByteCnt, unsigned srcNetNodeId );
268
+
269
+
270
+  //
271
+  // DSP to Host message functions
272
+  // 
273
+
274
+  // Is a msg from the DSP waiting to be picked up by the host?  (host <- DSP)
275
+  // 0  = no msgs are waiting or the msg queue is locked by the DSP process.
276
+  // >0 = the size of the buffer required to hold the next msg returned via 
277
+  // cmRtSysReceiveMsg().
278
+  unsigned  cmRtSysIsMsgWaiting(  cmRtSysH_t h );
279
+
280
+  // Copy the next available msg sent from the DSP process to the host into the host supplied msg buffer
281
+  // pointed to by 'msgBufPtr'.  Set 'msgDataPtr' to NULL to receive msg by callback from cmRtSysCfg_t.clientCbFunc.
282
+  // Returns kBufTooSmallRtRC if msgDataPtr[msgByteCnt] is too small to hold the msg.
283
+  // Returns kNoMsgWaitingRtRC if no messages are waiting for delivery or the msg queue is locked by the DSP process.
284
+  // Returns kOkRtRC if a msg was delivered.
285
+  // Call cmRtSysIsMsgWaiting() prior to calling this function to get
286
+  // the size of the data buffer required to hold the next message.
287
+  cmRtRC_t  cmRtSysReceiveMsg(    cmRtSysH_t h,  void* msgDataPtr, unsigned msgByteCnt );
288
+
289
+
290
+  // Fill an audio system status record.
291
+  void      cmRtSysStatus(  cmRtSysH_t h, unsigned rtSubIdx, cmRtSysStatus_t* statusPtr );
292
+
293
+  // Enable cmRtSysStatus_t notifications to be sent periodically to the host.
294
+  // Set rtSubIdx to cmInvalidIdx to enable/disable all sub-systems.
295
+  // The notifications occur approximately every cmRtSysCfg_t.meterMs milliseconds.
296
+  void cmRtSysStatusNotifyEnable( cmRtSysH_t, unsigned rtSubIdx, bool enableFl );
297
+
298
+  // Return a pointer the context record associated with a sub-system
299
+  cmRtSysCtx_t* cmRtSysContext( cmRtSysH_t h, unsigned rtSubIdx );
300
+
301
+  // Return the count of audio sub-systems.
302
+  // This is the same as the count of cfg recds passed to cmRtSystemInitialize().
303
+  unsigned cmRtSysSubSystemCount( cmRtSysH_t h );
304
+
305
+  // Audio system test and example function.
306
+  void      cmRtSysTest( cmRpt_t* rpt, int argc, const char* argv[] );
307
+
308
+
309
+
310
+#ifdef __cplusplus
311
+}
312
+#endif
313
+
314
+#endif

+ 99
- 0
cmRtSysMsg.h View File

@@ -0,0 +1,99 @@
1
+#ifndef cmRtSysMsg_h
2
+#define cmRtSysMsg_h
3
+
4
+#ifdef __cplusplus
5
+extern "C" {
6
+#endif
7
+
8
+  /// Reserved DSP message selector id's (second field of all host<->audio system messages)
9
+  enum
10
+  {
11
+    kMidiMsgArraySelRtId = 1000,
12
+    kMidiSysExSelRtId,
13
+    kUiDrvrSelRtId,    // cmUiDriverArg_t message to/from the UI driver
14
+    kUiSelRtId,      // cmUiDriverArg-t message from the UI mgr to a client 
15
+    kUiMstrSelRtId,  // indicates a cmDspUiHdr_t msg containing master control information for the audio system
16
+    kStatusSelRtId,  // indicates the msg is of type cmRtSysStatus_t
17
+    kNetSyncSelRtId,   // sent with a cmDspNetMsg_t object  
18
+  };
19
+
20
+  typedef struct
21
+  {
22
+    unsigned rtSubIdx;
23
+    unsigned selId;  // Message selector id See kXXXSelRtId above
24
+  } cmRtSysMsgHdr_t;
25
+
26
+  // All of the UI messages that create a UI control contain an array of integers
27
+  // as in the 'value' field. The array contains the id's associated with
28
+  // the different programmable paramters which are part of the control.
29
+  // For example a slider control has minimum,maximum, step size, and value 
30
+  // parameters. The location in the array is hard coded according to the
31
+  // parameters meaning but the actual value of the id is left up to the 
32
+  // engine. This allows the engine to use whatever values work best for
33
+  // it on a per instance basis. 
34
+
35
+
36
+  // Header record for all messages between the host and the DSP controllers.
37
+  typedef struct
38
+  {
39
+    cmRtSysMsgHdr_t hdr;
40
+    unsigned     devIdx;
41
+    unsigned     chIdx;
42
+    bool         inFl;
43
+    unsigned     ctlId;
44
+    double       value;
45
+  } cmRtSysMstr_t;
46
+
47
+
48
+
49
+  /// Control id's used to identify the control type of master contols.
50
+  enum
51
+  {
52
+    kSliderUiRtId = 0,
53
+    kMeterUiRtId  = 1,
54
+    kMuteUiRtId   = 2,
55
+    kToneUiRtId   = 3,
56
+    kPassUiRtId   = 4
57
+  };
58
+
59
+
60
+  /// Audio sub-system status record - this message can be transmitted to the host at
61
+  /// periodic intervals.  See cmRtSysStatusNotifyEnable().
62
+  /// When transmitted to the host this record acts as the message header.
63
+  /// This header is followed by two arrays of doubles containing the input and output meter values
64
+  /// associated with the input and output audio devices.
65
+  /// Message Layout: [ rtSubIdx kStatusSelId cmRtSysStatus_t iMeterArray[iMeterCnt] oMeterArray[oMeterCnt] ]
66
+  typedef struct
67
+  {
68
+    cmRtSysMsgHdr_t hdr;
69
+
70
+    unsigned updateCnt;    ///< count of callbacks from the audio devices.
71
+    unsigned wakeupCnt;    ///< count of times the audio system thread has woken up after the cond. var has been signaled by the audio update thread.
72
+    unsigned msgCbCnt;     ///< count of msgs delivered via cmRtCallback() .
73
+    unsigned audioCbCnt;   ///< count of times the DSP execution was requested via cmRtCallback().    
74
+
75
+    unsigned iDevIdx;      ///< Input device index
76
+    unsigned oDevIdx;      ///< Output device index
77
+
78
+    unsigned overflowCnt;  ///< count of times the audio input buffers overflowed
79
+    unsigned underflowCnt; ///< count of times the audio output buffers underflowed
80
+    unsigned iMeterCnt;    ///< count of input meter channels
81
+    unsigned oMeterCnt;    ///< count of output meter channels
82
+    
83
+  } cmRtSysStatus_t;
84
+
85
+
86
+  typedef struct
87
+  {
88
+    cmRtSysMsgHdr_t hdr;
89
+    unsigned     devIdx;
90
+    unsigned     portIdx;
91
+    unsigned     msgCnt;
92
+    // cmMidiMsg msgArray[msgCnt]
93
+  } cmRtSysMidi_t;
94
+
95
+#ifdef __cplusplus
96
+}
97
+#endif
98
+
99
+#endif

+ 509
- 0
cmUiRtSysMstr.c View File

@@ -0,0 +1,509 @@
1
+#include "cmGlobal.h"
2
+#include "cmFloatTypes.h"
3
+#include "cmRpt.h"
4
+#include "cmErr.h"
5
+#include "cmCtx.h"
6
+#include "cmMem.h"
7
+#include "cmMallocDebug.h"
8
+#include "cmJson.h"
9
+#include "cmThread.h"
10
+#include "cmUdpPort.h"
11
+#include "cmUdpNet.h"
12
+#include "cmRtSysMsg.h"
13
+#include "cmRtSys.h"
14
+#include "cmUiDrvr.h"
15
+#include "cmUi.h"
16
+#include "cmUiRtSysMstr.h"
17
+
18
+enum
19
+{
20
+  kLabelAmId,
21
+  kInSliderAmId,
22
+  kInMeterAmId,
23
+  kInToneAmId,
24
+  kInPassAmId,
25
+  kInMuteAmId,
26
+  kOutSliderAmId,
27
+  kOutMeterAmId,
28
+  kOutToneAmId,
29
+  kOutPassAmId,
30
+  kOutMuteAmId,
31
+  kAmCnt
32
+};
33
+
34
+
35
+enum
36
+{
37
+  kMinDb =  24,
38
+  kMaxDb = -24,
39
+  kMtrMin  = 0,
40
+  kMtrMax  = 100
41
+};
42
+
43
+typedef struct cmAmPanel_str
44
+{
45
+  unsigned              rtSubIdx;
46
+
47
+  unsigned              panelId;
48
+
49
+  unsigned              updateId;
50
+  unsigned              wakeupId;
51
+  unsigned              msgCbId;
52
+  unsigned              audioCbId;
53
+
54
+  unsigned              updateCnt;
55
+  unsigned              wakeupCnt;
56
+  unsigned              msgCbCnt;
57
+  unsigned              audioCbCnt;
58
+
59
+  unsigned              baseOutId;
60
+  unsigned              iDevIdx;
61
+  unsigned              oDevIdx;
62
+  unsigned              iChCnt;
63
+  unsigned              oChCnt;
64
+  
65
+  unsigned              a[ kAmCnt ];
66
+
67
+
68
+  struct cmAmPanel_str* link;
69
+} cmAmPanel_t;
70
+
71
+typedef struct
72
+{
73
+  cmErr_t      err;
74
+  unsigned     appId;
75
+  cmUiH_t      uiH;
76
+  cmRtSysH_t   asH;
77
+  unsigned     nextId;
78
+  cmAmPanel_t* list;
79
+} cmAm_t;
80
+
81
+cmUiRtMstrH_t cmUiRtMstrNullHandle = cmSTATIC_NULL_HANDLE;
82
+
83
+cmAm_t* _cmUiAmHandleToPtr( cmUiRtMstrH_t h )
84
+{
85
+  cmAm_t* p = (cmAm_t*)h.h;
86
+  assert( p!=NULL);
87
+  return p;
88
+}
89
+
90
+cmAmRC_t _cmUiAmFreePanels( cmAm_t* p, bool callDriverFl )
91
+{
92
+  cmAmRC_t       rc = kOkAmRC;
93
+  cmAmPanel_t* pp = p->list;
94
+  
95
+  while( pp != NULL )
96
+  {
97
+    cmAmPanel_t* np = pp->link;
98
+
99
+    unsigned panelId = pp->panelId;
100
+
101
+    if( callDriverFl )
102
+      if( cmUiClearPanel( p->uiH, p->appId, panelId ) != kOkUiRC )
103
+      {
104
+        rc = cmErrMsg(&p->err,kUiFailAmRC,"The panel %i clear failed.",panelId);
105
+        goto errLabel;
106
+      }
107
+
108
+    cmMemFree(pp);
109
+
110
+    pp = np;
111
+  }
112
+
113
+  p->nextId = 0;
114
+  p->list   = NULL;
115
+ 
116
+ errLabel:
117
+  return rc;
118
+}
119
+
120
+
121
+cmAmRC_t _cmUiAmFree( cmAm_t* p )
122
+{
123
+  _cmUiAmFreePanels(p,false);
124
+
125
+  if( cmUiDestroyApp( p->uiH, p->appId ) != kOkUiRC )
126
+    cmErrMsg(&p->err,kUiFailAmRC,"UI Mgr. app destroy failed.");
127
+    
128
+  cmMemFree(p);
129
+  return kOkAmRC;
130
+}
131
+
132
+cmAmRC_t cmUiRtSysMstrAlloc( cmCtx_t* ctx, cmUiRtMstrH_t* hp, cmUiH_t uiH, cmRtSysH_t asH, unsigned appId )
133
+{
134
+  cmAmRC_t rc = kOkAmRC;
135
+  
136
+  if((rc = cmUiRtSysMstrFree(hp)) != kOkAmRC )
137
+    return rc;
138
+
139
+  cmAm_t* p = cmMemAllocZ(cmAm_t,1);
140
+  cmErrSetup(&p->err,&ctx->rpt,"Audio System Master UI");
141
+
142
+  p->appId  = appId;
143
+  p->uiH    = uiH;
144
+  p->asH    = asH;
145
+  p->nextId = 0;
146
+
147
+    // allocate the UI Mgr. app. slot for the audio system master control UI.
148
+  if( cmUiCreateApp( uiH, appId, cmInvalidId ) != kOkUiRC )
149
+  {
150
+    rc = cmErrMsg(&p->err,kUiFailAmRC,"The UI Mgr. failed while creating the Audio System UI app. slot.");
151
+    goto errLabel;
152
+  }
153
+
154
+
155
+  hp->h     = p;
156
+ errLabel:
157
+  if( rc != kOkAmRC )
158
+    _cmUiAmFree(p);
159
+  return rc;
160
+}
161
+
162
+cmAmRC_t cmUiRtSysMstrFree(  cmUiRtMstrH_t* hp )
163
+{
164
+  cmAmRC_t rc = kOkAmRC;
165
+
166
+  if(hp==NULL || cmUiRtSysMstrIsValid(*hp)==false )
167
+    return kOkAmRC;
168
+
169
+  cmAm_t* p = _cmUiAmHandleToPtr(*hp);
170
+
171
+  if((rc = _cmUiAmFree(p)) != kOkAmRC )
172
+    return rc;
173
+
174
+  hp->h = NULL;
175
+
176
+  return rc;
177
+}
178
+
179
+bool     cmUiRtSysMstrIsValid( cmUiRtMstrH_t h )
180
+{ return h.h != NULL; }
181
+
182
+
183
+cmAmRC_t cmUiRtSysMstrInitialize( cmUiRtMstrH_t amH, const cmRtSysCtx_t* c, const cmChar_t* inDevLabel, const cmChar_t* outDevLabel )
184
+{
185
+  cmAmRC_t rc       = kOkAmRC;
186
+  cmAm_t*  p        = _cmUiAmHandleToPtr(amH);
187
+  cmUiH_t  uiH      = p->uiH;
188
+  unsigned panelId  = cmInvalidId;
189
+  unsigned colW     = 50;
190
+  unsigned ctlW     = 45;
191
+  unsigned n        = 31;
192
+  cmChar_t chNumStr[ n+1 ];
193
+  int      w;
194
+  cmAmPanel_t* pp = NULL;
195
+
196
+
197
+  // This function is called once for each audio sub-system.
198
+  // If this is the first call in the sequence then clear the previous setup.
199
+  if( c->rtSubIdx == 0 )
200
+  {
201
+    if((rc = _cmUiAmFreePanels(p,true)) != kOkAmRC )
202
+      goto errLabel;
203
+
204
+    assert(p->list == NULL );
205
+  }
206
+
207
+  // create the panel recd and link it to the beginning of the list
208
+  pp = cmMemAllocZ(cmAmPanel_t,1);
209
+
210
+  pp->link     = p->list;    
211
+  p->list      = pp;
212
+  pp->rtSubIdx = c->rtSubIdx;
213
+  pp->iDevIdx  = c->ss->args.inDevIdx;
214
+  pp->oDevIdx  = c->ss->args.outDevIdx;
215
+  pp->iChCnt   = c->iChCnt;
216
+  pp->oChCnt   = c->oChCnt;
217
+
218
+  
219
+  pp->panelId           = p->nextId++;  
220
+  pp->updateId          = p->nextId++;
221
+  pp->wakeupId          = p->nextId++;
222
+  pp->msgCbId           = p->nextId++;
223
+  pp->audioCbId         = p->nextId++;
224
+
225
+  pp->a[kLabelAmId]     = p->nextId;
226
+  pp->a[kInSliderAmId]  = p->nextId += c->iChCnt;
227
+  pp->a[kInMeterAmId]   = p->nextId += c->iChCnt;
228
+  pp->a[kInToneAmId]    = p->nextId += c->iChCnt;
229
+  pp->a[kInPassAmId]    = p->nextId += c->iChCnt;
230
+  pp->a[kInMuteAmId]    = p->nextId += c->iChCnt;
231
+
232
+  pp->baseOutId         = p->nextId += c->iChCnt;  
233
+
234
+  pp->a[kOutSliderAmId] = pp->baseOutId;
235
+  pp->a[kOutMeterAmId]  = p->nextId += c->oChCnt;
236
+  pp->a[kOutToneAmId]   = p->nextId += c->oChCnt;
237
+  pp->a[kOutPassAmId]   = p->nextId += c->oChCnt;
238
+  pp->a[kOutMuteAmId]   = p->nextId += c->oChCnt;
239
+  p->nextId += c->oChCnt;
240
+
241
+  panelId = pp->panelId;
242
+
243
+  if( cmUiCreatePanel(uiH, p->appId, panelId, "Master", 0 ) != kOkUiRC )
244
+  {
245
+    rc = cmErrMsg(&p->err,kUiFailAmRC,"Panel %i create failed.",panelId);
246
+    goto errLabel;
247
+  }
248
+
249
+  cmUiSetFillRows( uiH, p->appId, panelId, true );
250
+  cmUiCreateProgress(uiH, p->appId, panelId, pp->updateId, "Update",  0, 0, 1, 0 );
251
+  cmUiCreateProgress(uiH, p->appId, panelId, pp->wakeupId, "Wakeup",  0, 0, 1, 0 );
252
+  cmUiCreateProgress(uiH, p->appId, panelId, pp->msgCbId,  "Message", 0, 0, 1, 0 );
253
+  cmUiCreateProgress(uiH, p->appId, panelId, pp->audioCbId,"Audio",   0, 0, 1, 0 );
254
+  cmUiSetFillRows( uiH, p->appId, panelId, false );
255
+
256
+  cmUiNewLine(     uiH, p->appId, panelId );
257
+  cmUiCreateLabel( uiH, p->appId, panelId, cmInvalidId, inDevLabel, kInsideUiFl | kLeftUiFl ); 
258
+  cmUiNewLine(     uiH, p->appId, panelId );
259
+
260
+  unsigned i;
261
+  for(i=0; i<c->iChCnt; ++i)
262
+  {
263
+    snprintf(chNumStr,n,"%i",i);
264
+    
265
+    cmUiSetNextW(     uiH, p->appId, panelId, ctlW );
266
+    cmUiCreateLabel(  uiH, p->appId, panelId, cmInvalidId, chNumStr, 0 );
267
+    cmUiCreateVSlider(uiH, p->appId, panelId, pp->a[kInSliderAmId] + i, NULL,     0, kMinDb,  kMaxDb, 0.1, 0 );
268
+    cmUiPlaceRight(   uiH, p->appId, panelId );
269
+    cmUiCreateVMeter( uiH, p->appId, panelId, pp->a[kInMeterAmId]  + i, NULL,     0, kMtrMin, kMtrMax, 0 ); 
270
+    w = cmUiSetW(     uiH, p->appId, panelId, ctlW );
271
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kInToneAmId]   + i, "T",      0, false );
272
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kInPassAmId]   + i, "P",      0, false );
273
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kInMuteAmId]   + i, "M",      0, false );
274
+    cmUiSetW(         uiH, p->appId, panelId, w );
275
+    cmUiSetBaseCol( uiH, p->appId, panelId, 5 + (i+1)*colW);
276
+  }
277
+
278
+  cmUiSetBaseCol(  uiH, p->appId, panelId, 0);
279
+  cmUiNewLine(     uiH, p->appId, panelId );
280
+  cmUiCreateLabel( uiH,p->appId, panelId, cmInvalidId, outDevLabel, kInsideUiFl | kLeftUiFl ); 
281
+  cmUiNewLine(     uiH, p->appId, panelId );
282
+
283
+  for(i=0; i<c->oChCnt; ++i)
284
+  {
285
+    snprintf(chNumStr,n,"%i",i);
286
+    
287
+    cmUiSetNextW(     uiH, p->appId, panelId, ctlW );
288
+    cmUiCreateLabel(  uiH, p->appId, panelId, cmInvalidId, chNumStr, 0 );
289
+    cmUiCreateVSlider(uiH, p->appId, panelId, pp->a[kOutSliderAmId] + i, NULL,     0, kMinDb,  kMaxDb, 0.1, 0 );
290
+    cmUiPlaceRight(   uiH, p->appId, panelId );
291
+    cmUiCreateVMeter( uiH, p->appId, panelId, pp->a[kOutMeterAmId]  + i, NULL,     0, kMtrMin, kMtrMax, 0 ); 
292
+    w = cmUiSetW(     uiH, p->appId, panelId, ctlW );
293
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kOutToneAmId]   + i, "T",      0, false );
294
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kOutPassAmId]   + i, "P",      0, false );
295
+    cmUiCreateCheck(  uiH, p->appId, panelId, pp->a[kOutMuteAmId]   + i, "M",      0, false );
296
+    cmUiSetW(         uiH, p->appId, panelId, w );
297
+    cmUiSetBaseCol( uiH, p->appId, panelId, 5 + (i+1)*colW);
298
+  }
299
+
300
+ errLabel:
301
+  return rc;
302
+}
303
+
304
+
305
+cmAmPanel_t* _cmUiAmFindPanel( cmAm_t* p, unsigned panelId, bool errFl )
306
+{
307
+  cmAmPanel_t* pp = p->list;
308
+  for(; pp!=NULL; pp=pp->link)
309
+    if( pp->panelId == panelId )
310
+      return pp;
311
+
312
+  if( errFl )
313
+    cmErrMsg(&p->err,kPanelNotFoundAmRC,"The panel %i was not found.",panelId);
314
+
315
+  return NULL;
316
+}
317
+
318
+unsigned  _cmUiAmCtlTypeId( cmAm_t* p, cmAmPanel_t* pp, cmUiCId_t cId, unsigned usrId,
319
+  unsigned                          sliderId, unsigned toneId, unsigned passId, unsigned muteId )
320
+{
321
+    switch( cId )
322
+    {
323
+      case kSliderUiCId:
324
+        assert( pp->a[sliderId] <= usrId && usrId < pp->a[sliderId]+pp->oChCnt);
325
+        return sliderId;
326
+        break;
327
+
328
+      case kCheckUiCId:
329
+        if( pp->a[toneId] <= usrId && usrId < pp->a[toneId]+pp->oChCnt )
330
+          return toneId;
331
+
332
+        if( pp->a[passId] <= usrId && usrId < pp->a[passId]+pp->oChCnt )
333
+          return passId;
334
+
335
+        if( pp->a[muteId] <= usrId && usrId < pp->a[muteId]+pp->oChCnt )
336
+          return muteId;
337
+        break;
338
+
339
+      default:
340
+        break;
341
+    
342
+  }
343
+
344
+  return cmInvalidId;
345
+}
346
+
347
+
348
+cmUiRC_t cmUiRtSysMstrOnUiEvent( cmUiRtMstrH_t h, const cmUiDriverArg_t* a )
349
+{
350
+  cmUiRC_t      rc       = kOkUiRC;
351
+  cmAm_t*       p        = _cmUiAmHandleToPtr(h);
352
+  cmAmPanel_t*  pp;
353
+  cmRtSysMstr_t r;
354
+  unsigned      typeId;
355
+  bool          tabSelFl = a->dId==kSetValDId && a->cId == kPanelUiCId;
356
+  
357
+  if((pp = _cmUiAmFindPanel( p, a->panelId, !tabSelFl )) == NULL)
358
+  {
359
+    if( tabSelFl )
360
+      return kOkUiRC;
361
+
362
+    return cmErrLastRC(&p->err);
363
+  }
364
+
365
+  // if the panel tab was selected/deslected ival will be equal to 1/0
366
+  if( a->usrId == pp->panelId )
367
+  {
368
+    cmRtSysStatusNotifyEnable(p->asH, pp->rtSubIdx, a->ival );
369
+    return rc;
370
+  }
371
+
372
+  // based on the usrId determine which control generated the event
373
+  if( a->usrId >= pp->baseOutId )
374
+    typeId = _cmUiAmCtlTypeId(p,pp,a->cId,a->usrId,kOutSliderAmId,kOutToneAmId,kOutPassAmId,kOutMuteAmId);
375
+  else
376
+    typeId = _cmUiAmCtlTypeId(p,pp,a->cId,a->usrId,kInSliderAmId,kInToneAmId,kInPassAmId,kInMuteAmId);
377
+
378
+  
379
+  // this control is not a slider or check btn so ignore it
380
+  if( typeId == cmInvalidId )
381
+    return rc;
382
+
383
+  
384
+  unsigned asInFl  = 0;
385
+  unsigned asCtlId = cmInvalidId;
386
+  unsigned asCh    = a->usrId - pp->a[typeId];
387
+  double   asValue = 0;
388
+
389
+  switch( typeId )
390
+  {
391
+    case kInSliderAmId: 
392
+      asInFl  = 1;
393
+      asCtlId = kSliderUiRtId;
394
+      asValue = a->fval;
395
+      break;
396
+
397
+    case kInToneAmId:   
398
+      asInFl  = 1;
399
+      asCtlId = kToneUiRtId;
400
+      asValue = a->ival;
401
+      break;
402
+
403
+    case kInPassAmId:   
404
+      asInFl  = 1;
405
+      asCtlId = kPassUiRtId;
406
+      asValue = a->ival;
407
+      break;
408
+
409
+    case kInMuteAmId:   
410
+      asInFl  = 1;;
411
+      asCtlId = kMuteUiRtId;
412
+      asValue = a->ival;
413
+      break;
414
+
415
+    case kOutSliderAmId: 
416
+      asCtlId = kSliderUiRtId;
417
+      asValue = a->fval;
418
+      break;
419
+
420
+    case kOutToneAmId:   
421
+      asCtlId = kToneUiRtId;
422
+      asValue = a->ival;
423
+      break;
424
+
425
+    case kOutPassAmId:   
426
+      asCtlId = kPassUiRtId;
427
+      asValue = a->ival;
428
+      break;
429
+
430
+    case kOutMuteAmId:   
431
+      asCtlId = kMuteUiRtId;
432
+      asValue = a->ival;
433
+      break;
434
+
435
+  }
436
+
437
+  unsigned asDevIdx = asInFl ? pp->iDevIdx : pp->oDevIdx;
438
+
439
+  r.hdr.rtSubIdx  = pp->rtSubIdx;
440
+  r.hdr.selId      = kUiMstrSelRtId;
441
+  r.devIdx    = asDevIdx;
442
+  r.chIdx     = asCh;
443
+  r.inFl      = asInFl;
444
+  r.ctlId     = asCtlId;
445
+  r.value     = asValue;
446
+
447
+  if( cmRtSysDeliverMsg(p->asH,  &r, sizeof(r), cmInvalidId ) != kOkRtRC )
448
+     rc  = cmErrMsg(&p->err,kSubSysFailUiRC,"Audio System master control UI message delivery to the audio system failed.");
449
+
450
+  return rc;
451
+}
452
+
453
+int _cmUiAmLinToDb( double v )
454
+{
455
+  if( v <= 0 )
456
+    return 0;
457
+
458
+  v = round(20.0*log10(v)+100.0);
459
+  return cmMin(kMtrMax,cmMax(kMtrMin,v));
460
+  
461
+} 
462
+
463
+cmUiRC_t cmUiRtSysMstrOnStatusEvent( cmUiRtMstrH_t h, const cmRtSysStatus_t* m, const double* iMeterArray, const double* oMeterArray )
464
+{
465
+  cmAm_t*      p        = _cmUiAmHandleToPtr(h);
466
+  cmAmPanel_t* pp       = p->list;
467
+
468
+  for(; pp!=NULL; pp=pp->link)
469
+    if(pp->rtSubIdx == m->hdr.rtSubIdx )
470
+      break;
471
+
472
+  if( pp == NULL )
473
+    return cmErrMsg(&p->err,kPanelNotFoundUiRC,"The panel associated with Audio system index %i could not be found.",m->hdr.rtSubIdx);
474
+
475
+  cmUiSetInt(p->uiH, p->appId, pp->updateId,  m->updateCnt  != pp->updateCnt );
476
+  cmUiSetInt(p->uiH, p->appId, pp->wakeupId,  m->wakeupCnt  != pp->wakeupCnt );
477
+  cmUiSetInt(p->uiH, p->appId, pp->msgCbId,   m->msgCbCnt   != pp->msgCbCnt );
478
+  cmUiSetInt(p->uiH, p->appId, pp->audioCbId, m->audioCbCnt != pp->audioCbCnt );
479
+
480
+  pp->updateCnt = m->updateCnt;
481
+  pp->wakeupCnt = m->wakeupCnt;
482
+  pp->msgCbCnt  = m->msgCbCnt;
483
+  pp->audioCbCnt= m->audioCbCnt;
484
+
485
+  unsigned i;
486
+
487
+  for(i=0; i<m->iMeterCnt; ++i)
488
+    cmUiSetInt(p->uiH, p->appId, pp->a[kInMeterAmId]+i,  _cmUiAmLinToDb(iMeterArray[i]) );
489
+
490
+  for(i=0; i<m->oMeterCnt; ++i)
491
+    cmUiSetInt(p->uiH, p->appId, pp->a[kOutMeterAmId]+i, _cmUiAmLinToDb(oMeterArray[i])  );
492
+
493
+  return kOkUiRC;
494
+}
495
+
496
+void cmUiRtSysMstrClearStatus( cmUiRtMstrH_t h )
497
+{
498
+  cmAm_t*  p        = _cmUiAmHandleToPtr(h);
499
+
500
+  cmAmPanel_t* pp = p->list;
501
+  for(; pp!=NULL; pp=pp->link)
502
+  {
503
+    cmUiSetInt(p->uiH, p->appId, pp->updateId,  0 );
504
+    cmUiSetInt(p->uiH, p->appId, pp->wakeupId,  0 );
505
+    cmUiSetInt(p->uiH, p->appId, pp->msgCbId,   0 );
506
+    cmUiSetInt(p->uiH, p->appId, pp->audioCbId, 0 );
507
+  }
508
+
509
+}

+ 40
- 0
cmUiRtSysMstr.h View File

@@ -0,0 +1,40 @@
1
+#ifndef cmUiRtSysMstr_h
2
+#define cmUiRtSysMstr_h
3
+
4
+#ifdef __cplusplus
5
+extern "C" {
6
+#endif
7
+
8
+  enum
9
+  {
10
+    kOkAmRC = cmOkRC,
11
+    kUiFailAmRC,
12
+    kPanelNotFoundAmRC
13
+  };
14
+
15
+  typedef cmHandle_t cmUiRtMstrH_t;
16
+  typedef cmRC_t     cmAmRC_t;
17
+
18
+  extern cmUiRtMstrH_t cmUiRtMstrNullHandle;
19
+
20
+  cmAmRC_t cmUiRtSysMstrAlloc( cmCtx_t* ctx, cmUiRtMstrH_t* hp, cmUiH_t uiH, cmRtSysH_t asH, unsigned appId );
21
+  cmAmRC_t cmUiRtSysMstrFree(  cmUiRtMstrH_t* hp );
22
+
23
+  bool     cmUiRtSysMstrIsValid( cmUiRtMstrH_t h );
24
+
25
+  cmAmRC_t cmUiRtSysMstrInitialize( cmUiRtMstrH_t h, const cmRtSysCtx_t* c, const cmChar_t* inDevLabel, const cmChar_t* outDevLabel );
26
+
27
+  // Receive UI events.
28
+  cmUiRC_t cmUiRtSysMstrOnUiEvent( cmUiRtMstrH_t h, const cmUiDriverArg_t* a );
29
+
30
+  // Receive UI status events
31
+  cmUiRC_t cmUiRtSysMstrOnStatusEvent( cmUiRtMstrH_t h, const cmRtSysStatus_t* m, const double* iMeterArray, const double* oMeterArray );
32
+
33
+  // Clear the status indicators.
34
+  void cmUiRtSysMstrClearStatus( cmUiRtMstrH_t h );
35
+
36
+#ifdef __cplusplus
37
+}
38
+#endif
39
+
40
+#endif

Loading…
Cancel
Save