瀏覽代碼

cmProc5.h/c : Added cmGoldCode.

master
kevin 9 年之前
父節點
當前提交
b1ff1dfb07
共有 2 個文件被更改,包括 289 次插入0 次删除
  1. 220
    0
      cmProc5.c
  2. 69
    0
      cmProc5.h

+ 220
- 0
cmProc5.c 查看文件

@@ -16,7 +16,11 @@
16 16
 #include "cmProcObj.h"
17 17
 #include "cmProcTemplate.h"
18 18
 #include "cmMath.h"
19
+#include "cmFile.h"
20
+#include "cmTime.h"
21
+#include "cmMidi.h"
19 22
 #include "cmProc.h"
23
+#include "cmProc2.h"
20 24
 #include "cmProc5.h"
21 25
 
22 26
 #include "cmVectOps.h"
@@ -123,3 +127,219 @@ cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* inpV, unsigned procSmpCn
123 127
 }
124 128
 
125 129
 
130
+//=======================================================================================================================
131
+double _cmGoldSigSinc( double t, double T )
132
+{
133
+  double x = t/T;
134
+  return x == 0 ? 1.0 : sin(M_PI*x)/(M_PI*x);         
135
+}
136
+
137
+void _cmGoldSigRaisedCos(  cmSample_t* yV, int yN, double sPc, double beta )
138
+{
139
+  int i;
140
+  
141
+  for(i=0; i<yN; ++i)
142
+  {
143
+    double t   = i - yN/2;
144
+    double den = 1 - (4*(beta*beta)*(t*t) / (sPc*sPc));
145
+    double a;
146
+      
147
+    if(fabs(den) < 0.00001 )
148
+      a = 1;
149
+    else
150
+      a = cos(M_PI * beta * t/ sPc ) / den;
151
+
152
+    yV[i] = _cmGoldSigSinc(t,sPc) * a;  
153
+  }
154
+}
155
+
156
+void _cmGoldSigConv( cmGoldSig_t* p, unsigned chIdx )
157
+{
158
+  int i;
159
+  int sPc = p->a.samplesPerChip;
160
+  int osf = p->a.rcosOSFact;
161
+
162
+  // for each bit in the spreading-code
163
+  for(i=0; i<p->mlsN; ++i)
164
+  {
165
+    int j = (i*sPc) + sPc/2;  // index into bbV[] of center of impulse response
166
+    int k = j - (sPc*osf)/2;  // index into bbV[] of start of impulse response
167
+    int h;
168
+
169
+    // for each sample in the impulse response
170
+    for(h=0; h<p->rcosN; ++h,++k)
171
+    {
172
+     
173
+      while( k<0 )
174
+        k += p->sigN;
175
+
176
+      while( k>=p->sigN )
177
+        k -= p->sigN;
178
+
179
+      p->ch[chIdx].bbV[k] += p->ch[chIdx].pnV[i] * p->rcosV[h];     
180
+    }
181
+  }
182
+}
183
+
184
+void _cmGoldSigModulate( cmGoldSig_t* p, unsigned chIdx )
185
+{
186
+  unsigned    i;
187
+  double      rps = 2.0 * M_PI * p->a.carrierHz / p->a.srate;
188
+  cmSample_t* yV  = p->ch[chIdx].mdV;
189
+  cmSample_t* bbV = p->ch[chIdx].bbV;
190
+
191
+  for(i=0; i<p->sigN; ++i)
192
+    yV[ i ] = bbV[i]*cos(rps*i) + bbV[i]*sin(rps*i);
193
+
194
+  // apply a half Hann envelope to the onset/offset of the id signal
195
+  if( p->a.envMs > 0 )
196
+  {
197
+    unsigned   wndMs = p->a.envMs * 2;
198
+    unsigned   wndN  = wndMs * p->a.srate / 1000;
199
+    wndN += wndN % 2 ? 0 : 1;   // force the window length to be odd
200
+    unsigned   wNo2 = wndN/2 + 1;
201
+    cmSample_t wndV[ wndN ];
202
+    cmVOS_Hann(wndV,wndN);
203
+    cmVOS_MultVV(yV,wNo2,wndV);
204
+    cmVOS_MultVV(yV + p->sigN - wNo2, wNo2, wndV + wNo2 - 1);
205
+  }
206
+
207
+}
208
+
209
+cmGoldSig_t* cmGoldSigAlloc( cmCtx* ctx, cmGoldSig_t* p, const cmGoldSigArg_t* a )
210
+{
211
+  cmGoldSig_t* op = cmObjAlloc(cmGoldSig_t,ctx,p);
212
+  
213
+  if( a != NULL )  
214
+    if( cmGoldSigInit(op,a) != cmOkRC )
215
+      cmGoldSigFree(&op);
216
+
217
+  return op;
218
+
219
+}
220
+
221
+cmRC_t cmGoldSigFree( cmGoldSig_t** pp )
222
+{
223
+  cmRC_t rc = cmOkRC;
224
+
225
+  if( pp == NULL || *pp == NULL )
226
+    return rc;
227
+
228
+  cmGoldSig_t* p = *pp;
229
+
230
+  if((rc = cmGoldSigFinal(p)) != cmOkRC )
231
+    return rc;
232
+  
233
+  unsigned i;
234
+  for(i=0; i<p->a.chN; ++i)
235
+  {
236
+    cmMemFree(p->ch[i].bbV);
237
+    cmMemFree(p->ch[i].mdV);
238
+  }
239
+  
240
+  cmMemFree(p->ch);
241
+  cmMemFree(p->rcosV);
242
+  cmMemFree(p->pnM);
243
+  cmMemFree(p);
244
+  *pp = NULL;
245
+
246
+  return rc;
247
+}
248
+
249
+cmRC_t cmGoldSigInit( cmGoldSig_t* p, const cmGoldSigArg_t* a )
250
+{
251
+  cmRC_t      rc = cmOkRC;
252
+  unsigned    i;
253
+  
254
+  p->a      = *a;                                            // store arg recd
255
+  p->ch     = cmMemResizeZ(cmGoldSigCh_t,p->ch,a->chN);  // alloc channel array
256
+  p->mlsN   = (1 << a->lfsrN) - 1;                           // calc spreading code length
257
+  p->rcosN  = a->samplesPerChip * a->rcosOSFact;             // calc rcos imp. resp. length
258
+  p->rcosN += (p->rcosN % 2)==0;                             // force rcos imp. length odd               
259
+  p->rcosV  = cmMemResizeZ(cmSample_t,p->rcosV,p->rcosN);  // alloc rcos imp. resp. vector
260
+  p->pnM    = cmMemResizeZ(int,p->pnM,p->mlsN*a->chN);   // alloc spreading-code mtx
261
+  p->sigN   = p->mlsN * a->samplesPerChip;                   // calc audio signal length
262
+
263
+  // generate spreading codes
264
+  if( cmGenGoldCodes(a->lfsrN, a->mlsCoeff0, a->mlsCoeff1, a->chN, p->pnM, p->mlsN ) == false )
265
+  {
266
+    rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Unable to generate sufficient balanced Gold codes.");
267
+    goto errLabel;
268
+  }
269
+
270
+  // generate the rcos impulse response
271
+  _cmGoldSigRaisedCos(p->rcosV,p->rcosN,a->samplesPerChip,a->rcosBeta);
272
+
273
+  // for each channel
274
+  for(i=0; i<a->chN; ++i)
275
+  {
276
+    // Note: if (i*p->mlsN) is set to 0 in the following line then all channels
277
+    // will use the same spreading code.
278
+    p->ch[i].pnV = p->pnM + (i*p->mlsN);                        // get ch. spreading code
279
+    p->ch[i].bbV = cmMemResizeZ(cmSample_t,p->ch[i].bbV,p->sigN); // alloc baseband signal vector
280
+    p->ch[i].mdV = cmMemResizeZ(cmSample_t,p->ch[i].mdV,p->sigN); // alloc output audio vector
281
+
282
+    // Convolve spreading code with rcos impulse reponse to form baseband signal.
283
+    _cmGoldSigConv(p, i );     
284
+
285
+    // Modulate baseband signal to carrier frq. and apply attack/decay envelope.
286
+    _cmGoldSigModulate(p, i );
287
+  }
288
+
289
+ errLabel:
290
+  if((rc = cmErrLastRC(&p->obj.err)) != cmOkRC )
291
+    cmGoldSigFree(&p);
292
+
293
+  return rc;
294
+}
295
+
296
+cmRC_t cmGoldSigFinal( cmGoldSig_t* p )
297
+{ return cmOkRC; }
298
+
299
+cmRC_t cmGoldSigWrite( cmCtx* ctx, cmGoldSig_t* p, const char* fn )
300
+{
301
+  cmVectArray_t* vap = NULL;
302
+  unsigned       i;
303
+
304
+  vap = cmVectArrayAlloc(ctx,kSampleVaFl);
305
+
306
+  for(i=0; i<p->a.chN; ++i)
307
+  {
308
+    cmVectArrayAppendS(vap,p->ch[i].bbV,p->sigN);
309
+    cmVectArrayAppendS(vap,p->ch[i].mdV,p->sigN);
310
+  }
311
+
312
+  cmVectArrayWrite(vap,fn);
313
+
314
+  cmVectArrayFree(&vap);
315
+
316
+  return cmOkRC;
317
+}
318
+
319
+
320
+cmRC_t cmGoldSigGen( cmGoldSig_t* p, unsigned chIdx, unsigned prefixN, unsigned dsN, unsigned *bsiV, unsigned bsiN, double noiseGain, cmSample_t** yVRef, unsigned* yNRef )
321
+{
322
+  unsigned    yN = prefixN + bsiN * (p->sigN + dsN);
323
+  cmSample_t* yV = cmMemAllocZ(cmSample_t,yN);
324
+  unsigned    i;
325
+
326
+  cmVOS_Random(yV, yN, -noiseGain, noiseGain );
327
+
328
+  for(i=0; i<bsiN; ++i)
329
+  {
330
+    bsiV[i] = prefixN + i*(p->sigN + dsN);
331
+    
332
+    cmVOS_AddVV(yV + bsiV[i], p->sigN, p->ch[chIdx].mdV );
333
+  }
334
+  
335
+  if( yVRef != NULL )
336
+    *yVRef = yV;
337
+
338
+  if( yNRef != NULL )
339
+    *yNRef = yN;
340
+
341
+  return cmOkRC;  
342
+}
343
+
344
+
345
+

+ 69
- 0
cmProc5.h 查看文件

@@ -39,7 +39,76 @@ extern "C" {
39 39
   cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* in, unsigned procSmpCnt,  double* outV, unsigned chCnt );
40 40
 
41 41
 
42
+  //=======================================================================================================================
43
+  // Gold Code Signal Generator
44
+  //
45
+
46
+  typedef struct
47
+  {
48
+    unsigned chN;              // count of channels (each channel has a unique id)   
49
+    double   srate;            // system sample rate (samples/second)
50
+    unsigned lfsrN;            // linear feedback shift register (LFSR) length used to form Gold codes
51
+    unsigned mlsCoeff0;        // LFSR coeff. 0
52
+    unsigned mlsCoeff1;        // LFSR coeff. 1
53
+    unsigned samplesPerChip;   // samples per spreading code bit
54
+    double   rcosBeta;         // raised cosine impulse response beta coeff.
55
+    unsigned rcosOSFact;       // raised cosine impulse response oversample factor
56
+    double   carrierHz;        // carrier frequency
57
+    double   envMs;            // attack/decay envelope duration
58
+  } cmGoldSigArg_t;
59
+
60
+  typedef struct
61
+  {
62
+    int*        pnV;  // pnV[ mlsN ]  spread code (aliased from pnM[:,i])
63
+    cmSample_t* bbV;  // bbV[ sigN ]  baseband signal  at audio rate
64
+    cmSample_t* mdV;  // mdV[ sigN ]  modulated signal at audio rate
65
+  } cmGoldSigCh_t;
66
+
67
+  typedef struct 
68
+  {
69
+    cmObj          obj;         // 
70
+    cmGoldSigArg_t a;           // argument record
71
+    cmGoldSigCh_t* ch;          // ch[ chN ] channel array
72
+    int*           pnM;         // pnM[mlsN,chN] (aliased to ch[].pnV)
73
+    cmSample_t*    rcosV;       // rcosV[rcosN] raised cosine impulse response
74
+    unsigned       rcosN;       // length of raised cosine impulse response
75
+    unsigned       mlsN;        // length of Gold codes (Maximum length sequence length)
76
+    unsigned       sigN;        // length of channel signals bbV[] and mdV[]  
77
+  } cmGoldSig_t;
78
+
79
+
80
+  cmGoldSig_t* cmGoldSigAlloc( cmCtx* ctx, cmGoldSig_t* p, const cmGoldSigArg_t* a );
81
+  cmRC_t cmGoldSigFree( cmGoldSig_t** pp );
82
+
83
+  cmRC_t cmGoldSigInit( cmGoldSig_t* p, const cmGoldSigArg_t* a );
84
+  cmRC_t cmGoldSigFinal( cmGoldSig_t* p );
85
+  
86
+  cmRC_t cmGoldSigWrite( cmCtx* ctx, cmGoldSig_t* p, const char* fn );
87
+
88
+  // Generate a signal consisting of  underlying white noise with 
89
+  // bsiN repeated copies of the id signal associated with 
90
+  // channel 'chIdx'. Each discrete id signal copy is separated by 'dsN' samples.
91
+  // The signal will be prefixed with 'prefixN' samples of silence (noise).
92
+  // On return sets 'yVRef' to point to the generated signal and 'yNRef'
93
+  // to the count of samples in 'yVRef'.
94
+  // On error sets yVRef to NULL and  yNRef to zero.
95
+  // The vector returned in 'yVRef' should be freed via atMemFree().
96
+  // On return sets bsiV[bsiN] to the onset sample index of each id signal copy.
97
+  // The background noise signal is limited to the range -noiseGain to noiseGain.
98
+  cmRC_t cmGoldSigGen( 
99
+    cmGoldSig_t*   p, 
100
+    unsigned      chIdx, 
101
+    unsigned      prefixN, 
102
+    unsigned      dsN, 
103
+    unsigned     *bsiV, 
104
+    unsigned      bsiN, 
105
+    double        noiseGain, 
106
+    cmSample_t**  yVRef, 
107
+    unsigned*     yNRef );
108
+
109
+  cmRC_t cmGoldSigTest( cmCtx* ctx );
42 110
 
111
+  
43 112
 #ifdef __cplusplus
44 113
 }
45 114
 #endif

Loading…
取消
儲存