Browse Source

cmScoreMatchGraphic.h/c, Makefile.am : Initial commit.

master
Kevin Larke 8 years ago
parent
commit
01bf7de3bd
3 changed files with 522 additions and 5 deletions
  1. 2
    5
      Makefile.am
  2. 488
    0
      app/cmScoreMatchGraphic.c
  3. 32
    0
      app/cmScoreMatchGraphic.h

+ 2
- 5
Makefile.am View File

@@ -73,9 +73,6 @@ cmHDR += src/libcm/cmDList.h src/libcm/cmDListTpl.h
73 73
 cmHDR += src/libcm/cmProcObj.h src/libcm/cmProc.h src/libcm/cmProc2.h src/libcm/cmProc3.h src/libcm/cmProc4.h src/libcm/cmProc5.h src/libcm/cmProcTest.h
74 74
 cmSRC += src/libcm/cmProcObj.c src/libcm/cmProc.c src/libcm/cmProc2.c src/libcm/cmProc3.c src/libcm/cmProc4.c src/libcm/cmProc5.c src/libcm/cmProcTest.c
75 75
 
76
-
77
-cmHDR += src/libcm/app/cmOnset.h src/libcm/app/cmTimeLine.h src/libcm/app/cmScore.h src/libcm/app/cmScoreProc.h 
78
-
79 76
 cmHDR += src/libcm/cmErr.h src/libcm/cmCtx.h src/libcm/cmRpt.h src/libcm/cmGlobal.h src/libcm/cmComplexTypes.h src/libcm/cmFloatTypes.h src/libcm/cmPrefix.h
80 77
 cmSRC += src/libcm/cmErr.c src/libcm/cmCtx.c src/libcm/cmRpt.c src/libcm/cmGlobal.c src/libcm/cmComplexTypes.c
81 78
 
@@ -147,8 +144,8 @@ cmHDR += src/libcm/cmProcObj.h src/libcm/cmProc.h src/libcm/cmProc2.h src/libcm/
147 144
 cmSRC += src/libcm/cmProcObj.c src/libcm/cmProc.c src/libcm/cmProc2.c src/libcm/cmProc3.c src/libcm/cmProc4.c src/libcm/cmProc5.c src/libcm/cmProcTest.c
148 145
 
149 146
 
150
-cmHDR += src/libcm/app/cmOnset.h src/libcm/app/cmTimeLine.h src/libcm/app/cmScore.h src/libcm/app/cmScoreProc.h src/libcm/app/cmXScore.h 
151
-cmSRC += src/libcm/app/cmOnset.c src/libcm/app/cmTimeLine.c src/libcm/app/cmScore.c src/libcm/app/cmScoreProc.c src/libcm/app/cmXScore.c
147
+cmHDR += src/libcm/app/cmOnset.h src/libcm/app/cmTimeLine.h src/libcm/app/cmScore.h src/libcm/app/cmScoreProc.h src/libcm/app/cmXScore.h src/libcm/app/cmScoreMatchGraphic.h
148
+cmSRC += src/libcm/app/cmOnset.c src/libcm/app/cmTimeLine.c src/libcm/app/cmScore.c src/libcm/app/cmScoreProc.c src/libcm/app/cmXScore.c src/libcm/app/cmScoreMatchGraphic.c
152 149
 
153 150
 cmHDR += src/libcm/app/cmSdb.h  src/libcm/app/cmTakeSeqBldr.h  src/libcm/app/cmDspPgmJsonToDot.h
154 151
 cmSRC += src/libcm/app/cmSdb.c  src/libcm/app/cmTakeSeqBldr.c  src/libcm/app/cmDspPgmJsonToDot.c

+ 488
- 0
app/cmScoreMatchGraphic.c View File

@@ -0,0 +1,488 @@
1
+#include "cmPrefix.h"
2
+#include "cmGlobal.h"
3
+#include "cmFloatTypes.h"
4
+#include "cmRpt.h"
5
+#include "cmErr.h"
6
+#include "cmCtx.h"
7
+#include "cmMem.h"
8
+#include "cmMallocDebug.h"
9
+#include "cmLinkedHeap.h"
10
+#include "cmTime.h"
11
+#include "cmMidi.h"
12
+#include "cmLex.h"
13
+#include "cmCsv.h"
14
+#include "cmSymTbl.h"
15
+#include "cmMidiFile.h"
16
+#include "cmAudioFile.h"
17
+#include "cmTimeLine.h"
18
+#include "cmText.h"
19
+#include "cmFile.h"
20
+#include "cmScore.h"
21
+#include "cmScoreMatchGraphic.h"
22
+
23
+enum
24
+{
25
+  kBarSmgFl     = 0x0001,
26
+  kNoteSmgFl    = 0x0002,
27
+  kMidiSmgFl    = 0x0004,
28
+  kNoMatchSmgFl = 0x0008
29
+};
30
+
31
+typedef struct cmSmgBox_str
32
+{
33
+  unsigned             flags;
34
+  unsigned             id;    // csvEventId or midiUid
35
+  unsigned             left;
36
+  unsigned             top;
37
+  unsigned             width;
38
+  unsigned             height;
39
+  cmChar_t*            text;
40
+  struct cmSmgBox_str* link;  
41
+} cmSmgBox_t;
42
+
43
+typedef struct cmSmgLine_str
44
+{
45
+  cmSmgBox_t* b0;
46
+  cmSmgBox_t* b1;
47
+  struct cmSmgLine_str* link;
48
+} cmSmgLine_t;
49
+
50
+typedef struct cmSmgLoc_str
51
+{
52
+  cmSmgBox_t* bV;
53
+} cmSmgLoc_t;
54
+
55
+typedef struct
56
+{
57
+  unsigned    type;
58
+  unsigned    csvEventId;
59
+  unsigned    locIdx;
60
+  cmSmgBox_t* box;
61
+} cmSmgSc_t;
62
+
63
+typedef struct cmSmgMatch_str
64
+{
65
+  cmSmgSc_t*             score;
66
+  struct cmSmgMatch_str* link;
67
+} cmSmgMatch_t;
68
+
69
+typedef struct
70
+{
71
+  unsigned      uid;
72
+  unsigned      pitch;
73
+  unsigned      vel;
74
+  cmSmgMatch_t* matchV;
75
+  cmSmgBox_t*   box;
76
+} cmSmgMidi_t;
77
+
78
+
79
+typedef struct
80
+{
81
+  cmErr_t      err;
82
+  cmSmgSc_t*   scV;
83
+  unsigned     scN;
84
+  cmSmgMidi_t* mV;
85
+  unsigned     mN;
86
+  cmSmgLoc_t*  locV;
87
+  unsigned     locN;
88
+  cmSmgLine_t* lines;
89
+} cmSmg_t;
90
+
91
+cmSmgH_t cmSmgNullHandle = cmSTATIC_NULL_HANDLE;
92
+
93
+cmSmg_t* _cmSmgHandleToPtr( cmSmgH_t h )
94
+{
95
+  cmSmg_t* p = (cmSmg_t*)h.h;
96
+  assert(p!=NULL);
97
+  return p;
98
+}
99
+
100
+cmSmgRC_t _cmSmgFree( cmSmg_t* p )
101
+{
102
+  unsigned i;
103
+  
104
+  for(i=0; i<p->mN; ++i)
105
+  {
106
+    cmSmgMatch_t* m0 = p->mV[i].matchV;
107
+    cmSmgMatch_t* m1 = NULL;
108
+    while(m0!=NULL)
109
+    {
110
+      m1 = m0->link;
111
+      cmMemFree(m0);
112
+      m0 = m1;
113
+    }    
114
+  }
115
+
116
+  for(i=0; i<p->locN; ++i)
117
+  {
118
+    cmSmgBox_t* b0 = p->locV[i].bV;
119
+    cmSmgBox_t* b1 = NULL;
120
+    while(b0!=NULL)
121
+    {
122
+      b1 = b0->link;
123
+      cmMemFree(b0->text);
124
+      cmMemFree(b0);
125
+      b0 = b1;
126
+    }
127
+  }
128
+
129
+  cmSmgLine_t* l0 = p->lines;
130
+  cmSmgLine_t* l1 = NULL;
131
+  while( l0 != NULL )
132
+  {
133
+    l1 = l0->link;
134
+    cmMemFree(l0);
135
+    l0 = l1;
136
+  }
137
+  
138
+  cmMemFree(&p->scV);
139
+  cmMemFree(&p->mV);
140
+  cmMemFree(&p->locV);
141
+  cmMemFree(p);
142
+  return kOkSmgRC;
143
+}
144
+
145
+cmSmgBox_t*  _cmSmgInsertBox( cmSmg_t* p, unsigned locIdx, unsigned flags, unsigned id, cmChar_t* text )
146
+{
147
+  assert( locIdx < p->locN );
148
+  
149
+  cmSmgBox_t* b = cmMemAllocZ(cmSmgBox_t,1);
150
+  b->flags = flags;
151
+  b->id    = id;
152
+  b->text  = text;
153
+
154
+  if( p->locV[locIdx].bV == NULL )
155
+    p->locV[locIdx].bV = b;
156
+  else
157
+  {
158
+    cmSmgBox_t* b0 = p->locV[locIdx].bV;
159
+    while( b0->link!=NULL )
160
+      b0 = b0->link;
161
+
162
+    b0->link = b;
163
+  }
164
+
165
+  return b;
166
+}
167
+
168
+cmSmgRC_t _cmSmgInitFromScore( cmCtx_t* ctx, cmSmg_t* p, const cmChar_t* scoreFn )
169
+{
170
+  cmSmgRC_t  rc    = kOkSmgRC;
171
+  cmScH_t    scH   = cmScNullHandle;
172
+  unsigned   i,j,k;
173
+  
174
+  if( cmScoreInitialize(ctx,&scH,scoreFn,44100.0, NULL, 0, NULL, NULL, cmSymTblNullHandle ) != kOkScRC )
175
+    return cmErrMsg(&p->err,kScoreFailSmgRC,"Score initializatio failed on '%s'.",cmStringNullGuard(scoreFn));
176
+
177
+  p->scN  = cmScoreEvtCount(scH);
178
+  p->scV  = cmMemAllocZ(cmSmgSc_t,p->scN);
179
+  
180
+  p->locN = cmScoreLocCount(scH);
181
+  p->locV = cmMemAllocZ(cmSmgLoc_t,p->locN);
182
+
183
+  // for each score location
184
+  for(i=0,k=0; i<cmScoreLocCount(scH); ++i)
185
+  {
186
+    cmScoreLoc_t* l = cmScoreLoc(scH,i);
187
+
188
+    // for each event in location i
189
+    for(j=0; j<l->evtCnt; ++j)
190
+    {
191
+      const cmScoreEvt_t* e = l->evtArray[j];
192
+      
193
+      switch( e->type)
194
+      {
195
+        case kBarEvtScId:
196
+        case kNonEvtScId:
197
+          {
198
+            unsigned  flags = e->type==kNonEvtScId ? kNoteSmgFl : kBarSmgFl;
199
+            cmChar_t* text  = NULL;
200
+          
201
+            assert( k < p->scN );
202
+
203
+            p->scV[k].type       = e->type;
204
+            p->scV[k].csvEventId = e->csvEventId;
205
+            p->scV[k].locIdx     = i;
206
+
207
+            if( e->type == kBarEvtScId )
208
+              text = cmTsPrintfP(NULL,"%i",e->barNumb);
209
+            else
210
+              text = cmMemAllocStr( cmMidiToSciPitch( e->pitch, NULL, 0));
211
+    
212
+            p->scV[k].box = _cmSmgInsertBox(p, i, flags, e->csvEventId, text );
213
+          
214
+            k += 1;
215
+          }
216
+          break;
217
+      }
218
+    }
219
+  }
220
+
221
+  cmScoreFinalize(&scH);
222
+  
223
+  return rc;
224
+}
225
+
226
+cmSmgRC_t _cmSmgInitFromMidi( cmCtx_t* ctx, cmSmg_t* p, const cmChar_t* midiFn )
227
+{
228
+  cmSmgRC_t     rc  = kOkSmgRC;
229
+  cmMidiFileH_t mfH = cmMidiFileNullHandle;
230
+  unsigned      i,j;
231
+  
232
+  if( cmMidiFileOpen(ctx, &mfH, midiFn ) != kOkMfRC )
233
+    return cmErrMsg(&p->err,kMidiFileFailSmgRC,"MIDI file open failed on '%s'.",cmStringNullGuard(midiFn));
234
+
235
+  const cmMidiTrackMsg_t** mV  = cmMidiFileMsgArray(mfH);
236
+  unsigned                 mN  = cmMidiFileMsgCount(mfH);
237
+
238
+  p->mV = cmMemAllocZ(cmSmgMidi_t,mN);
239
+  p->mN = mN;
240
+  
241
+  for(i=0,j=0; i<mN; ++i)
242
+    if( (mV[i]!=NULL) && cmMidiIsChStatus(mV[i]->status) && cmMidiIsNoteOn(mV[i]->status) && (mV[i]->u.chMsgPtr->d1>0) )          
243
+    {
244
+      p->mV[j].uid   = mV[i]->uid;
245
+      p->mV[j].pitch = mV[i]->u.chMsgPtr->d0;
246
+      p->mV[j].vel   = mV[i]->u.chMsgPtr->d1;
247
+    }
248
+  
249
+  cmMidiFileClose(&mfH);
250
+
251
+  return rc;
252
+}
253
+
254
+cmSmgRC_t cmScoreMatchGraphicAlloc( cmCtx_t* ctx, cmSmgH_t* hp, const cmChar_t* scoreFn, const cmChar_t* midiFn )
255
+{
256
+  cmSmgRC_t rc;
257
+  if((rc = cmScoreMatchGraphicFree(hp)) != kOkSmgRC )
258
+    return rc;
259
+
260
+  cmSmg_t* p = cmMemAllocZ(cmSmg_t,1);
261
+  cmErrSetup(&p->err,&ctx->rpt,"ScoreMatchGraphic");
262
+
263
+  if((rc = _cmSmgInitFromScore(ctx,p,scoreFn)) != kOkSmgRC )
264
+    goto errLabel;
265
+
266
+  if((rc = _cmSmgInitFromMidi(ctx,p,midiFn)) != kOkSmgRC )
267
+    goto errLabel;
268
+
269
+  hp->h = p;
270
+
271
+ errLabel:
272
+  if( rc != kOkSmgRC )
273
+    _cmSmgFree(p);
274
+  
275
+  return rc;
276
+}
277
+
278
+cmSmgRC_t cmScoreMatchGraphicFree( cmSmgH_t* hp )
279
+{
280
+  cmSmgRC_t rc = kOkSmgRC;
281
+  
282
+  if(hp==NULL || cmScoreMatchGraphicIsValid(*hp)==false)
283
+    return kOkSmgRC;
284
+
285
+  cmSmg_t* p = _cmSmgHandleToPtr(*hp);
286
+
287
+  if((rc = _cmSmgFree(p)) != kOkSmgRC )
288
+    return rc;
289
+
290
+  hp->h = NULL;
291
+  
292
+  return rc;
293
+}
294
+
295
+bool cmScoreMatchGraphic( cmSmgH_t h )
296
+{ return h.h != NULL; }
297
+
298
+cmSmgRC_t cmScoreMatchGraphicInsertMidi( cmSmgH_t h, unsigned midiUid, unsigned midiPitch, unsigned midiVel, unsigned csvScoreEventId )
299
+{
300
+  cmSmg_t* p = _cmSmgHandleToPtr(h);
301
+  unsigned i,j;
302
+
303
+  // for each MIDI event
304
+  for(i=0; i<p->mN; ++i)
305
+    if( p->mV[i].uid == midiUid )
306
+    {
307
+      // for each score record
308
+      for(j=0; j<p->scN; ++j)
309
+        if( p->scV[j].csvEventId == csvScoreEventId )
310
+        {
311
+          cmSmgMatch_t* m = cmMemAllocZ(cmSmgMatch_t,1);
312
+          
313
+          m->score = p->scV + j;
314
+
315
+          if( p->mV[i].matchV == NULL )
316
+            p->mV[i].matchV = m;
317
+          else
318
+          {
319
+            cmSmgMatch_t* m0 = p->mV[i].matchV;
320
+            while( m0->link != NULL )
321
+              m0 = m0->link;
322
+
323
+            m0->link = m;
324
+          }
325
+        }
326
+
327
+      return cmErrMsg(&p->err,kScoreFailSmgRC,"The score csv event id %i not found,",csvScoreEventId);
328
+    }
329
+  
330
+  return cmErrMsg(&p->err,kMidiFileFailSmgRC,"MIDI uid %i not found.",midiUid);
331
+}
332
+
333
+// Create a box for each MIDI event and a line for each
334
+// match beyond the first.
335
+void _cmSmgResolveMidi( cmSmg_t* p )
336
+{
337
+  unsigned prevLocIdx = 0;
338
+  unsigned i;
339
+  
340
+  // for each midi record
341
+  for(i=0; i<p->mN; ++i)
342
+  {
343
+    const cmSmgMatch_t* m = p->mV[i].matchV;
344
+
345
+    // get the score location for this midi event
346
+    unsigned locIdx = m==NULL ? prevLocIdx : m->score->locIdx;
347
+
348
+    unsigned flags  = kMidiSmgFl | (m==NULL ? kNoMatchSmgFl : 0);
349
+    
350
+    // set the text label for this event
351
+    cmChar_t* text  = cmMemAllocStr( cmMidiToSciPitch( p->mV[i].pitch, NULL, 0));
352
+
353
+    // insert a box to represent this midi event
354
+    cmSmgBox_t* box = _cmSmgInsertBox( p, locIdx, flags, p->mV[i].uid, text );
355
+
356
+    prevLocIdx = locIdx;
357
+
358
+    // if this midi event matched to multiple score positions
359
+    if( m != NULL && m->link != NULL )
360
+    {
361
+      // insert a line for each match after the first
362
+      m = m->link;
363
+      for(; m!=NULL; m=m->link )
364
+      {
365
+        cmSmgLine_t* l = cmMemAllocZ(cmSmgLine_t,1);
366
+        l->b0 = box;
367
+        l->b1 = m->score->box;
368
+
369
+        l->link  = p->lines;
370
+        p->lines = l;
371
+      }
372
+    }    
373
+  }
374
+}
375
+
376
+void _cmSmgLayout( cmSmg_t* p )
377
+{
378
+  unsigned i;
379
+  unsigned bordX = 5;
380
+  unsigned bordY = 5;
381
+  unsigned boxH  = 30;
382
+  unsigned boxW  = 30;
383
+  unsigned top   = boxH + bordY;
384
+  unsigned left  = bordX;
385
+  
386
+  for(i=0; i<p->locN; ++i)
387
+  {
388
+    cmSmgLoc_t* l = p->locV + i;
389
+    cmSmgBox_t* b = l->bV;
390
+    
391
+    for(; b!=NULL; b=b->link)
392
+    {
393
+      if( cmIsFlag(b->flags,kBarSmgFl) )
394
+        b->top = bordY;
395
+      else
396
+      {
397
+        b->top = top;
398
+        top   += boxH + bordY;
399
+      }
400
+      
401
+      b->left   = left;
402
+      b->width  = boxW;
403
+      b->height = boxH;
404
+    }
405
+
406
+    left += boxW + bordX;
407
+  }
408
+}
409
+
410
+void _cmSmgSvgSize( cmSmg_t* p, unsigned* widthRef, unsigned* heightRef )
411
+{
412
+  unsigned i;
413
+  unsigned maxWidth  = 0;
414
+  unsigned maxHeight = 0;
415
+  
416
+  for(i=0; i<p->locN; ++i)
417
+  {
418
+    cmSmgBox_t* b = p->locV[i].bV;
419
+    while( b != NULL )
420
+    {
421
+      if( b->left + b->width > maxWidth )
422
+        maxWidth = b->left + b->width;
423
+      
424
+      if( b->top + b->height > maxHeight )
425
+        maxHeight = b->top + b->height;
426
+    }
427
+  }
428
+
429
+  *widthRef  = maxWidth;
430
+  *heightRef = maxHeight;
431
+}
432
+
433
+cmSmgRC_t cmScoreMatchGraphicWrite( cmSmgH_t h, const cmChar_t* fn )
434
+{
435
+  cmSmg_t*  p         = _cmSmgHandleToPtr(h);
436
+  cmFileH_t fH        = cmFileNullHandle;
437
+  unsigned  svgHeight = 0;
438
+  unsigned  svgWidth  = 0;
439
+  unsigned  i;
440
+  
441
+  if( cmFileOpen(&fH,fn,kWriteFileFl,p->err.rpt) != kOkFileRC )
442
+    return cmErrMsg(&p->err,kFileFailScRC,"Graphic file create failed for '%s'.",cmStringNullGuard(fn));
443
+
444
+  _cmSmgSvgSize(p,&svgWidth,&svgHeight);
445
+
446
+  cmFilePrintf(fH,"<!DOCTYPE html>\n<html>\n<head><link rel=\"stylesheet\" type=\"text/css\" href=\"score0.css\"></head><body>\n<svg width=\"%i\" height=\"%i\">\n",svgWidth,svgHeight);
447
+
448
+  for(i=0; i<p->locN; ++i)
449
+  {
450
+    cmSmgBox_t* b = p->locV[i].bV;
451
+    while( b != NULL )
452
+    {
453
+      const cmChar_t* classStr = "score";
454
+
455
+      if( cmIsFlag(b->flags,kMidiSmgFl) )
456
+        classStr = "midi";
457
+
458
+      if( cmIsFlag(b->flags,kNoMatchSmgFl) )
459
+        if( cmIsFlag(b->flags,kMidiSmgFl) )
460
+          classStr = "midi_miss";
461
+      
462
+      if( cmIsFlag(b->flags,kNoMatchSmgFl) )
463
+        if( cmIsFlag(b->flags,kNoteSmgFl) )
464
+          classStr = "score_miss";
465
+
466
+      if( cmIsFlag(b->flags,kBarSmgFl) )
467
+        classStr = "bar";
468
+      
469
+      if( cmFilePrintf(fH,"<rect x=\"%i\" y=\"%i\" width=\"%i\" height=\"%i\" class=\"%s\"/>\n",b->left,b->top,b->width,b->height,classStr) != kOkFileRC )
470
+        return cmErrMsg(&p->err,kFileFailScRC,"File write failed on graphic file output.");
471
+
472
+      if( b->text != NULL )
473
+      {
474
+        unsigned tx = b->left + b->width/2;
475
+        unsigned ty = b->top  + 20; //g->height/2;
476
+        
477
+        if( cmFilePrintf(fH,"<text x=\"%i\" y=\"%i\" text-anchor=\"middle\" class=\"stext\">%s</text>\n",tx,ty,b->text) != kOkFileRC )
478
+          return cmErrMsg(&p->err,kFileFailScRC,"File write failed on graphic file output.");
479
+      }
480
+      
481
+    }
482
+  }
483
+    
484
+  cmFilePrint(fH,"</svg>\n</body>\n</html>\n");
485
+
486
+  cmFileClose(&fH);
487
+  return kOkSmgRC;
488
+}

+ 32
- 0
app/cmScoreMatchGraphic.h View File

@@ -0,0 +1,32 @@
1
+#ifndef cmScoreMatchGraphic_h
2
+#define cmScoreMatchGraphic_h
3
+
4
+#ifdef __cplusplus
5
+extern "C" {
6
+#endif
7
+
8
+  enum
9
+  {
10
+    kOkSmgRC = cmOkRC,
11
+    kFileSmgRC,
12
+    kScoreFailSmgRC,
13
+    kMidiFileFailSmgRC
14
+  };
15
+  
16
+  typedef cmRC_t     cmSmgRC_t;
17
+  typedef cmHandle_t cmSmgH_t;
18
+
19
+  extern cmSmgH_t cmSmgNullHandle;
20
+
21
+  cmSmgRC_t cmScoreMatchGraphicAlloc( cmCtx_t* ctx, cmSmgH_t* hp, const cmChar_t* scoreFn, const cmChar_t* midiFn );
22
+  cmSmgRC_t cmScoreMatchGraphicFree( cmSmgH_t* hp );
23
+  bool      cmScoreMatchGraphicIsValid( cmSmgH_t h );
24
+  cmSmgRC_t cmScoreMatchGraphicInsertMidi( cmSmgH_t h, unsigned midiUid, unsigned midiPitch, unsigned midiVel, unsigned csvScoreEventId ); 
25
+  cmSmgRC_t cmScoreMatchGraphicWrite( cmSmgH_t h, const cmChar_t* fn );
26
+  
27
+  
28
+#ifdef __cplusplus
29
+}
30
+#endif
31
+
32
+#endif

Loading…
Cancel
Save