Browse Source

cmMidiScoreFollow.h/c, Makefile.am : cmMidiScoreFollow.h/c initial commit.

master
kevin 8 years ago
parent
commit
d963fb2b77
3 changed files with 321 additions and 0 deletions
  1. 3
    0
      Makefile.am
  2. 293
    0
      app/cmMidiScoreFollow.c
  3. 25
    0
      app/cmMidiScoreFollow.h

+ 3
- 0
Makefile.am View File

@@ -77,6 +77,9 @@ cmSRC += src/libcm/cmProcObj.c src/libcm/cmProc.c src/libcm/cmProc2.c src/libcm/
77 77
 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
78 78
 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
79 79
 
80
+cmHDR += src/libcm/app/cmMidiScoreFollow.h
81
+cmSRC += src/libcm/app/cmMidiScoreFollow.c
82
+
80 83
 cmHDR += src/libcm/app/cmSdb.h  src/libcm/app/cmTakeSeqBldr.h  src/libcm/app/cmDspPgmJsonToDot.h
81 84
 cmSRC += src/libcm/app/cmSdb.c  src/libcm/app/cmTakeSeqBldr.c  src/libcm/app/cmDspPgmJsonToDot.c
82 85
 

+ 293
- 0
app/cmMidiScoreFollow.c View File

@@ -0,0 +1,293 @@
1
+#include "cmPrefix.h"
2
+#include "cmGlobal.h"
3
+#include "cmRpt.h"
4
+#include "cmErr.h"
5
+#include "cmCtx.h"
6
+#include "cmMem.h"
7
+#include "cmMallocDebug.h"
8
+#include "cmLinkedHeap.h"
9
+#include "cmFloatTypes.h"
10
+#include "cmComplexTypes.h"
11
+#include "cmFile.h"
12
+#include "cmFileSys.h"
13
+#include "cmJson.h"
14
+#include "cmSymTbl.h"
15
+#include "cmAudioFile.h"
16
+#include "cmText.h"
17
+#include "cmProcObj.h"
18
+#include "cmProcTemplate.h"
19
+#include "cmMath.h"
20
+#include "cmTime.h"
21
+#include "cmMidi.h"
22
+#include "cmMidiFile.h"
23
+#include "cmProc.h"
24
+#include "cmProc2.h"
25
+#include "cmVectOps.h"
26
+#include "cmTimeLine.h"
27
+#include "cmScore.h"
28
+#include "cmProc4.h"
29
+#include "cmMidiScoreFollow.h"
30
+#include "cmScoreMatchGraphic.h"
31
+
32
+typedef struct
33
+{
34
+  cmScMatcherResult_t* rV;       // rV[rN] - array of stored cmScMatcher callback records.
35
+  unsigned             rAllocN;  //
36
+  unsigned             rN;       //
37
+} _cmMsf_ScoreFollow_t;
38
+
39
+void _cmMsf_ReportScoreErrors( const _cmMsf_ScoreFollow_t* f, cmScH_t scH )
40
+{
41
+  unsigned scoreEvtN = cmScoreEvtCount(scH);
42
+  unsigned i,j;
43
+  
44
+  for(i=0; i<scoreEvtN; ++i)
45
+  {
46
+    const cmScoreEvt_t* e = cmScoreEvt(scH,i);
47
+    assert(e != NULL);
48
+
49
+    if( e->type == kNonEvtScId && cmIsNotFlag(e->flags,kSkipScFl) )
50
+    {
51
+      unsigned matchN = 0;
52
+      
53
+      for(j=0; j<f->rN; ++j)
54
+        if( f->rV[j].scEvtIdx == i )
55
+          matchN += 1;
56
+      
57
+      if( matchN != 1 )
58
+      {
59
+        const cmScoreLoc_t* l = cmScoreEvtLoc(scH,e);
60
+        assert(l != NULL);
61
+        printf("bar:%3i evtIdx:%5i pitch:%4s match:%i ",l->barNumb,e->index,cmMidiToSciPitch(e->pitch,NULL,0),matchN);
62
+
63
+        // print the midi event associated with multiple matches.
64
+        if( matchN > 1 )
65
+          for(j=0; j<f->rN; ++j)
66
+            if( f->rV[j].scEvtIdx == i )
67
+              printf("(%i %s) ",f->rV[j].muid, cmMidiToSciPitch(f->rV[j].pitch,NULL,0) );
68
+        
69
+        printf("\n");
70
+      }
71
+    }
72
+  }
73
+}
74
+
75
+void _cmMsf_ReportMidiErrors( const _cmMsf_ScoreFollow_t* f, cmScH_t scH, const cmMidiTrackMsg_t** m, unsigned mN)
76
+{
77
+  unsigned i,j;
78
+  unsigned lastBar = 0;
79
+  
80
+  // for each midi note-on msg
81
+  for(i=0; i<mN; ++i)
82
+  {    
83
+    if( (m[i]!=NULL) && cmMidiIsChStatus(m[i]->status) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) )          
84
+    {
85
+      unsigned matchN = 0;
86
+      
87
+      // find the note-on msg in the score-match result array
88
+      for(j=0; j<f->rN; ++j)
89
+        if( f->rV[j].muid == m[i]->uid )
90
+        {
91
+          if( f->rV[j].scEvtIdx != -1 )
92
+          {
93
+            const cmScoreEvt_t* e = cmScoreEvt(scH,f->rV[j].scEvtIdx);
94
+            if( e != NULL )
95
+            {
96
+              const cmScoreLoc_t* l = cmScoreEvtLoc(scH,e);
97
+              assert(l != NULL );
98
+              lastBar = l->barNumb;
99
+            }
100
+          }
101
+          
102
+          matchN += 1;
103
+          break;
104
+        }
105
+
106
+      if( matchN==0 )
107
+      {
108
+        printf("bar:%3i muid:%4i %s\n", lastBar, m[i]->uid, cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0));
109
+      }
110
+        
111
+    }
112
+  }
113
+}
114
+
115
+// Write one scScoreMatcherResult_t record to the file fH.
116
+unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcherResult_t* r )
117
+{
118
+  unsigned scUid = -1;
119
+  cmChar_t buf[6];
120
+  buf[0] = 0;
121
+  buf[5] = 0;
122
+  
123
+  cmScoreLoc_t* loc = NULL;
124
+    
125
+  if( r->scEvtIdx > 0 && r->scEvtIdx < cmScoreEvtCount(scH))
126
+  {
127
+    cmScoreEvt_t* e = cmScoreEvt(scH,r->scEvtIdx);
128
+    loc   = cmScoreEvtLoc(scH,e);
129
+    scUid = e->csvEventId;
130
+    cmMidiToSciPitch(e->pitch,buf,5);
131
+  }
132
+  
133
+  cmFilePrintf(fH,"m %3i %5i %4s %5i %4s %3i\n",
134
+    loc==NULL ? 0 : loc->barNumb,              // score evt bar
135
+    scUid,                                     // score event uuid
136
+    buf,                                       // score event pitch
137
+    r->muid,                                   // midi event uuid
138
+    cmMidiToSciPitch(r->pitch,NULL,0),         // midi event pitch
139
+    r->vel);                                   // midi event velocity
140
+
141
+  return scUid;
142
+}
143
+
144
+void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp )
145
+{
146
+  _cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg;
147
+  r->rV[r->rN++] = *rp;
148
+}
149
+
150
+cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
151
+{
152
+  cmMsfRC_t             rc          = kOkMsfRC;
153
+  //const cmChar_t* scoreFn         = cmFsMakeUserFn("src/kc/src/kc/data","mod2e","csv",NULL);
154
+  const cmChar_t*          scoreFn  = cmFsMakeUserFn("temp","a5","csv",NULL);
155
+  const cmChar_t*          midiFn   = cmFsMakeUserFn("media/projects/imag_themes/scores/gen","round1-utf8_11","mid",NULL);
156
+  const cmChar_t*          outFn    = cmFsMakeUserFn("temp","match","txt",NULL);
157
+  const cmChar_t*          svgFn    = cmFsMakeUserFn("temp","score0","html",NULL);
158
+  const cmChar_t*          tlBarFn  = cmFsMakeUserFn("temp",NULL,"time_line_temp","txt",NULL);
159
+  
160
+  double                   srate    = 96000.0;
161
+  cmScMatcher*             smp      = NULL;  
162
+  cmScH_t                  scH      = cmScNullHandle;
163
+  cmMidiFileH_t            mfH      = cmMidiFileNullHandle;
164
+  unsigned                 scWndN   = 10;
165
+  unsigned                 midiWndN = 7;
166
+  const cmMidiTrackMsg_t** m        = NULL;
167
+  unsigned                 mN       = 0;
168
+  unsigned                 scLocIdx = 0;
169
+  cmFileH_t                fH       = cmFileNullHandle;
170
+  cmSmgH_t                 smgH     = cmSmgNullHandle;
171
+  unsigned                 i;
172
+  cmErr_t                  err;
173
+  _cmMsf_ScoreFollow_t    sfr;
174
+  memset(&sfr,0,sizeof(sfr));
175
+
176
+  cmErrSetup(&err,&ctx->rpt,"cmMidiScoreFollow");
177
+
178
+  cmCtx* prCtx   = cmCtxAlloc(NULL, err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
179
+  
180
+  // initialize the score
181
+  if( cmScoreInitialize( ctx, &scH, scoreFn, srate, NULL, 0, NULL, NULL, cmSymTblNullHandle) != kOkScRC )
182
+  {
183
+    rc = cmErrMsg(&err,kFailMsfRC,"cmScoreInitialize() failed on %s",cmStringNullGuard(scoreFn));
184
+    goto errLabel;
185
+  }
186
+
187
+  // setup the callback record
188
+  if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
189
+  {
190
+    rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreFn));
191
+    goto errLabel;
192
+  }
193
+
194
+  sfr.rV = cmMemAllocZ(cmScMatcherResult_t,sfr.rAllocN);
195
+  sfr.rN = 0;
196
+  
197
+  // create a matcher
198
+  if((smp = cmScMatcherAlloc(prCtx, NULL, srate, scH, scWndN, midiWndN, _cmMsf_ScoreFollowCb, &sfr)) == NULL )
199
+  {
200
+    rc = cmErrMsg(&err,kFailMsfRC,"cmScMatcherAlloc() failed.");
201
+    goto errLabel;
202
+  }
203
+
204
+  // open the MIDI file
205
+  if( cmMidiFileOpen(ctx, &mfH, midiFn ) != kOkMfRC )
206
+  {
207
+    rc = cmErrMsg(&err,kFailMsfRC,"The MIDI file object could not be opened from '%s'.",cmStringNullGuard(midiFn));
208
+    goto errLabel;
209
+  }
210
+
211
+  // get a pointer to the MIDI msg array
212
+  if( (m = cmMidiFileMsgArray(mfH)) == NULL || (mN = cmMidiFileMsgCount(mfH)) == 0 )
213
+  {
214
+    rc = cmErrMsg(&err,kFailMsfRC,"The MIDI file object appears to be empty.");
215
+    goto errLabel;
216
+  }
217
+
218
+  // feed each MIDI note-on to the score follower
219
+  for(i=0; i<mN; ++i)
220
+    if( (m[i]!=NULL) && cmMidiIsChStatus(m[i]->status) && cmMidiIsNoteOn(m[i]->status) && (m[i]->u.chMsgPtr->d1>0) )          
221
+      if( cmScMatcherExec( smp, m[i]->amicro * srate / 1000000.0, m[i]->uid, m[i]->status, m[i]->u.chMsgPtr->d0, m[i]->u.chMsgPtr->d1, &scLocIdx ) != cmOkRC )
222
+      {
223
+        rc = cmErrMsg(&err,kFailMsfRC,"The score matcher exec failed.");
224
+        goto errLabel;
225
+      }
226
+
227
+
228
+  printf("MIDI notes:%i Score Events:%i\n",mN,cmScoreEvtCount(scH));
229
+
230
+  // create the output file
231
+  if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
232
+  {
233
+    rc = cmErrMsg(&err,kFailMsfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
234
+    goto errLabel;    
235
+  }
236
+
237
+  // allocate the graphics object
238
+  if( cmScoreMatchGraphicAlloc( ctx, &smgH, scoreFn, midiFn ) != kOkSmgRC )
239
+  {
240
+    rc = cmErrMsg(&err,kFailMsfRC,"Score Match Graphics allocation failed..");
241
+    goto errLabel;    
242
+  }
243
+
244
+
245
+  // for each score follower callback record 
246
+  for(i=0; i<sfr.rN; ++i)
247
+  {
248
+    // write the record to the output file
249
+    unsigned scUid = _cmMsf_WriteMatchFileLine( fH, scH, sfr.rV + i );
250
+    
251
+
252
+    // insert the event->score match in the score match graphics object
253
+    if( cmScoreMatchGraphicInsertMidi( smgH, sfr.rV[i].muid, sfr.rV[i].pitch, sfr.rV[i].vel, scUid ) != kOkSmgRC )
254
+    {
255
+      rc = cmErrMsg(&err,kFailMsfRC,"Score Match Graphics MIDI event insertion failed.");
256
+      goto errLabel;    
257
+    }
258
+
259
+  }
260
+
261
+  //_cmMsf_ReportScoreErrors(&sfr, scH );
262
+
263
+  //_cmMsf_ReportMidiErrors(&sfr, scH, m, mN);
264
+
265
+  //cmScorePrint(scH,&atc->ctx->rpt);
266
+  //cmMidiFilePrintMsgs( mfH, &atc->ctx->rpt );
267
+
268
+  // write the tracking match file as an SVG file.
269
+  cmScoreMatchGraphicWrite( smgH, svgFn );
270
+
271
+  // write a cmTimeLine file which contains markers at each bar position
272
+  //cmScoreMatchGraphicGenTimeLineBars(smgH, tlBarFn, srate );
273
+
274
+
275
+ errLabel:
276
+  
277
+  cmFileClose(&fH);
278
+  cmMemFree(sfr.rV);
279
+  cmMidiFileClose(&mfH);
280
+  cmScMatcherFree(&smp);
281
+  cmScoreFinalize(&scH);
282
+  cmScoreMatchGraphicFree(&smgH);
283
+
284
+  cmCtxFree(&prCtx);
285
+
286
+  cmFsFreeFn(scoreFn);
287
+  cmFsFreeFn(midiFn);
288
+  cmFsFreeFn(outFn);
289
+  cmFsFreeFn(svgFn);
290
+  cmFsFreeFn(tlBarFn);
291
+  
292
+  return rc;
293
+}

+ 25
- 0
app/cmMidiScoreFollow.h View File

@@ -0,0 +1,25 @@
1
+#ifndef cmMidiScoreFollow_h
2
+#define cmMidiScoreFollow_h
3
+
4
+
5
+#ifdef __cplusplus
6
+extern "C" {
7
+#endif
8
+
9
+  enum
10
+  {
11
+    kOkMsfRC = cmOkRC,
12
+    kFailMsfRC
13
+  };
14
+
15
+  typedef cmRC_t cmMsfRC_t;
16
+  
17
+
18
+  cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx );
19
+  
20
+#ifdef __cplusplus
21
+}
22
+#endif
23
+
24
+
25
+#endif

Loading…
Cancel
Save