Browse Source

cmXScore.h/c : Added 'tied_dur' field to cmXsNote_t for use in determining the length of a MIDI note events.

master
kevin 7 years ago
parent
commit
84c5097a8d
2 changed files with 59 additions and 38 deletions
  1. 57
    37
      app/cmXScore.c
  2. 2
    1
      app/cmXScore.h

+ 57
- 37
app/cmXScore.c View File

@@ -84,11 +84,13 @@ typedef struct cmXsNote_str
84 84
   unsigned                    staff;    // 1=treble 2=bass
85 85
   unsigned                    tick;     //
86 86
   unsigned                    duration; // duration in ticks
87
+  unsigned                    tied_dur; // duration in ticks (including all tied notes)
87 88
   double                      secs;     // absolute time in seconds
88 89
   double                      dsecs;    // delta time in seconds since previous event
89 90
   unsigned                    locIdx;   // location index (chords share the same location index)
90 91
   double                      rvalue;   // 1/rvalue = rythmic value (1/0.5 double whole 1/1 whole 1/2 half 1/4=quarter note, 1/8=eighth note, ...)
91 92
   const cmChar_t*             tvalue;   // text value
93
+  unsigned                    mf_uid;   // MIDI file uid assigned to this event
92 94
 
93 95
   unsigned                    evenGroupId;   // eveness group id
94 96
   unsigned                    dynGroupId;    // dynamics group id
@@ -239,8 +241,9 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
239 241
     n->mlink = note;
240 242
   }
241 243
 
242
-  note->voice = v;
243
-  note->uid   = p->nextUid++;
244
+  note->voice    = v;
245
+  note->uid      = p->nextUid++;
246
+  note->tied_dur = note->duration;
244 247
 
245 248
   return kOkXsRC;
246 249
 }
@@ -605,6 +608,7 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_
605 608
   note->rvalue   = rvalue;
606 609
   note->tvalue   = tvalue;
607 610
   note->duration = duration;
611
+  note->tied_dur = duration;
608 612
   note->meas     = meas;
609 613
   note->xmlNode  = noteXmlNode;
610 614
 
@@ -1065,6 +1069,7 @@ void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
1065 1069
 
1066 1070
 bool  _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, bool rptFl )
1067 1071
 {
1072
+  cmXsNote_t* nbp       = n0p;
1068 1073
   cmXsNote_t* nnp       = n0p->slink;  // begin w/ note following np
1069 1074
   unsigned    measNumb  = mp->number;
1070 1075
   cmChar_t    acc       = n0p->alter==-1?'b' : (n0p->alter==1?'#':' ');
@@ -1093,9 +1098,11 @@ bool  _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
1093 1098
       // if this note is tied to the originating note (np)
1094 1099
       if( nnp->voice->id == n0p->voice->id && nnp->step == n0p->step && nnp->octave == n0p->octave )
1095 1100
       {
1096
-        nnp->flags |= kTieProcXsFl;
1097
-        nnp->flags  = cmClrFlag(nnp->flags,kOnsetXsFl);
1098
-        n0p->tied   = nnp;
1101
+        nnp->flags    |= kTieProcXsFl;
1102
+        nnp->flags     = cmClrFlag(nnp->flags,kOnsetXsFl);
1103
+        n0p->tied      = nnp;
1104
+        nbp->tied_dur += nnp->duration;
1105
+        nnp->tied_dur  = 0;
1099 1106
 
1100 1107
         if( rptFl )
1101 1108
           printf("---> %i %i %s ",nnp->meas->number,nnp->tick,cmMidiToSciPitch(nnp->pitch,NULL,0));
@@ -1118,10 +1125,10 @@ bool  _cmXScoreFindTiedNote( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* n0p, boo
1118 1125
 
1119 1126
 void  _cmXScoreResolveTiesAndLoc( cmXScore_t* p )
1120 1127
 {
1121
-  unsigned n   = 0;
1122
-  unsigned m   = 0;
1123
-  bool     rptFl = false;
1124
-  cmXsPart_t* pp = p->partL;
1128
+  unsigned    n     = 0;        // count of notes which begin a tie
1129
+  unsigned    m     = 0;        // count of tied notes that are correctly terminated.
1130
+  bool        rptFl = false;
1131
+  cmXsPart_t* pp    = p->partL;
1125 1132
 
1126 1133
   // for each part
1127 1134
   for(; pp!=NULL; pp=pp->link)
@@ -1227,7 +1234,7 @@ cmXsNote_t*  _cmXScoreFindOverlappingNote( cmXScore_t* p, const cmXsNote_t* knp
1227 1234
           && cmIsFlag(np->flags,kOnsetXsFl)
1228 1235
           && knp->pitch == np->pitch
1229 1236
           && knp->tick >= np->tick 
1230
-          && knp->tick <  (np->tick + np->duration)  )
1237
+          && knp->tick <  (np->tick + np->tied_dur)  )
1231 1238
         {
1232 1239
           return np;
1233 1240
         }
@@ -1256,7 +1263,7 @@ void  _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
1256 1263
         if( cmIsFlag(np->flags,kOnsetXsFl) && (fnp = _cmXScoreFindOverlappingNote(p,np)) != NULL)
1257 1264
         {
1258 1265
           // is np entirely contained inside fnp
1259
-          bool embeddedFl = fnp->tick + fnp->duration > np->tick + np->duration;
1266
+          bool embeddedFl = fnp->tick + fnp->tied_dur > np->tick + np->tied_dur;
1260 1267
           
1261 1268
           //printf("bar=%3i %4s voice:%2i %2i : %7i %7i : %7i %7i : %7i : %c \n",np->meas->number,cmMidiToSciPitch(np->pitch,NULL,0),np->voice->id,fnp->voice->id,fnp->tick,fnp->tick+fnp->duration,np->tick,np->tick+np->duration, (fnp->tick+fnp->duration) - np->tick, embeddedFl ? 'E' : 'O');
1262 1269
 
@@ -1270,14 +1277,14 @@ void  _cmXScoreProcessOverlappingNotes( cmXScore_t* p )
1270 1277
           }
1271 1278
           else
1272 1279
           {
1273
-            int d = (fnp->tick+fnp->duration) - np->tick;
1280
+            int d = (fnp->tick+fnp->tied_dur) - np->tick;
1274 1281
 
1275 1282
             // shorten the first note
1276
-            if( d > 0 && d < fnp->duration )
1277
-              fnp->duration -= d;
1283
+            if( d > 0 && d < fnp->tied_dur )
1284
+              fnp->tied_dur -= d;
1278 1285
 
1279 1286
             // move the second note just past it
1280
-            np->tick       = fnp->tick + fnp->duration + 1;
1287
+            np->tick       = fnp->tick + fnp->tied_dur + 1;
1281 1288
           }
1282 1289
         }
1283 1290
     }
@@ -1404,7 +1411,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
1404 1411
       {
1405 1412
         if( cmIsFlag(np->flags,kMetronomeXsFl) )
1406 1413
         {
1407
-          double bps =  np->duration / 60.0;
1414
+          double bps =  np->tied_dur / 60.0;
1408 1415
 
1409 1416
           // t   b  t
1410 1417
           // - = -  -
@@ -1418,7 +1425,7 @@ cmXsRC_t _cmXScoreWriteScorePlotFile( cmXScore_t* p, const cmChar_t* fn )
1418 1425
           {
1419 1426
             onset_secs += (np->tick - tick0) / ticks_per_sec;
1420 1427
             tick0       = np->tick;
1421
-            cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->duration/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
1428
+            cmFilePrintf(fH,"n %f %f %i %s %s\n",onset_secs,np->tied_dur/ticks_per_sec,np->uid,cmMidiToSciPitch(np->pitch,NULL,0),cmIsFlag(np->flags,kGraceXsFl)?"G":"N");
1422 1429
           }
1423 1430
         }
1424 1431
       }
@@ -1700,7 +1707,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
1700 1707
               
1701 1708
             // set each grace note to have 1/20 of a second duration
1702 1709
             if( cmIsFlag(np->flags,kGraceXsFl) )
1703
-              np->duration = floor(ticksPerSec * graceDurSec);
1710
+              np->duration = np->tied_dur = floor(ticksPerSec * graceDurSec);
1704 1711
 
1705 1712
             gN += 1;
1706 1713
           } 
@@ -2938,7 +2945,7 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
2938 2945
     note->voice->id,
2939 2946
     note->locIdx,
2940 2947
     note->tick,
2941
-    note->duration,
2948
+    note->tied_dur,
2942 2949
     note->rvalue,
2943 2950
     N,B,R,G,D,C,e,d,t,P,s,S,H,T0,T1,O);
2944 2951
 
@@ -3072,8 +3079,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3072 3079
         {
3073 3080
           case kOnsetXsFl:
3074 3081
             {
3075
-              if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kNoteOnMdId,  np->pitch, np->vel ) != kOkMfRC
3076
-                ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kNoteOffMdId, np->pitch, 0 )       != kOkMfRC )
3082
+              if( np->tied_dur <= 0 )
3083
+                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i %s",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
3084
+              
3085
+              if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kNoteOnMdId,  np->pitch, np->vel, &np->mf_uid ) != kOkMfRC
3086
+                ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->tied_dur, kNoteOffMdId, np->pitch, 0, &np->mf_uid )       != kOkMfRC )
3077 3087
               {
3078 3088
                 rc = kMidiFailXsRC;
3079 3089
               }
@@ -3084,9 +3094,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3084 3094
           case kDampUpDnXsFl:
3085 3095
           case kSostDnXsFl:
3086 3096
             {
3097
+              if( np->duration <= 0 )
3098
+                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i",np->meas->number,np->tick);
3099
+              
3087 3100
               cmMidiByte_t d0     = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;              
3088
-              if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kCtlMdId, d0, 127 ) != kOkMfRC )
3089
-                ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0,   0 ) != kOkMfRC ) )
3101
+              if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kCtlMdId, d0, 127, &np->mf_uid ) != kOkMfRC )
3102
+                ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0,   0, &np->mf_uid ) != kOkMfRC ) )
3090 3103
               {
3091 3104
                 rc = kMidiFailXsRC;
3092 3105
               }
@@ -3094,7 +3107,7 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3094 3107
             break;
3095 3108
 
3096 3109
           case kMetronomeXsFl:
3097
-            if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
3110
+            if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration, &np->mf_uid ) != kOkMfRC )
3098 3111
               rc = kMidiFailXsRC;            
3099 3112
             break;
3100 3113
             
@@ -3141,6 +3154,7 @@ typedef struct cmXsSvgEvt_str
3141 3154
   unsigned         voice;     // score voice number
3142 3155
   unsigned         d0;        // MIDI d0   (barNumb)
3143 3156
   unsigned         d1;        // MIDI d1
3157
+  unsigned         mf_uid;
3144 3158
   struct cmXsSvgEvt_str* link;
3145 3159
 } cmXsSvgEvt_t;
3146 3160
 
@@ -3162,7 +3176,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
3162 3176
   unsigned        noteHeight = 10;
3163 3177
   cmChar_t*       fn0        = cmMemAllocStr( fn );  
3164 3178
   const cmChar_t* svgFn      = cmFsMakeFn(dir,fn0 = cmTextAppendSS(fn0,"_midi_svg"),"html",NULL);
3165
-  const cmChar_t* cssFn      = cmFsMakeFn(NULL,fn,"css",NULL);
3179
+  const cmChar_t* cssFn      = cmFsMakeFn(NULL,"score_midi_svg","css",NULL);
3166 3180
   cmChar_t*       t0         = NULL;  // temporary dynamic string
3167 3181
 
3168 3182
   cmMemFree(fn0);
@@ -3193,8 +3207,12 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
3193 3207
           if( cmSvgWriterRect(svgH, e->tick, e->d0 * noteHeight,  e->durTicks,  noteHeight-1, t0 ) != kOkSvgRC )
3194 3208
             rc = kSvgFailXsRC;
3195 3209
           else
3196
-            if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
3210
+          {
3211
+            t0 = cmTsPrintfP(t0,"%s %i",cmMidiToSciPitch( e->d0, NULL, 0),e->mf_uid);
3212
+            
3213
+            if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, t0, "pitch") != kOkSvgRC )
3197 3214
               rc = kSvgFailXsRC;
3215
+          }
3198 3216
         }
3199 3217
         break;
3200 3218
 
@@ -3241,7 +3259,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
3241 3259
 }
3242 3260
 
3243 3261
 
3244
-void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
3262
+void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1, unsigned mf_uid )
3245 3263
 {
3246 3264
   cmXsSvgEvt_t* e = cmLhAllocZ(p->lhH,cmXsSvgEvt_t,1);
3247 3265
   e->flags    = flags;
@@ -3250,6 +3268,8 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
3250 3268
   e->voice    = voice;
3251 3269
   e->d0       = d0;       // note=pitch bar=number pedal=ctl# metronome=BPM 
3252 3270
   e->d1       = d1;
3271
+  e->mf_uid   = mf_uid;
3272
+  
3253 3273
   if( mf->eol != NULL )
3254 3274
     mf->eol->link = e;
3255 3275
   else
@@ -3286,7 +3306,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
3286 3306
         if( cmIsFlag(note->flags,kMetronomeXsFl) )
3287 3307
         {
3288 3308
           // set BPM as d0
3289
-          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0);
3309
+          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0,note->mf_uid);
3290 3310
           continue;
3291 3311
           
3292 3312
         }
@@ -3295,21 +3315,21 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
3295 3315
         if( cmIsFlag(note->flags,kOnsetXsFl) )
3296 3316
         {
3297 3317
           unsigned d0      =  cmSciPitchToMidiPitch( note->step, note->alter, note->octave );
3298
-          unsigned durTick = note->duration;
3318
+          unsigned durTick = note->tied_dur;
3299 3319
           if( note->tied != NULL )
3300 3320
           {
3301 3321
             cmXsNote_t* tn = note->tied;
3302 3322
             for(; tn!=NULL; tn=tn->tied)
3303
-              durTick += tn->duration;
3323
+              durTick += tn->tied_dur;
3304 3324
           }
3305
-          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel);
3325
+          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,durTick,note->voice->id,d0,note->vel,note->mf_uid);
3306 3326
           continue;
3307 3327
         }
3308 3328
 
3309 3329
         // if this is a bar event
3310 3330
         if( cmIsFlag(note->flags,kBarXsFl) )
3311 3331
         {
3312
-          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
3332
+          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0, note->mf_uid);
3313 3333
           continue;
3314 3334
         }
3315 3335
 
@@ -3317,7 +3337,7 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
3317 3337
         if( cmIsFlag(note->flags,kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
3318 3338
         {
3319 3339
           unsigned d0 = cmIsFlag(note->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;          
3320
-          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127);
3340
+          _cmXsPushSvgEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127,note->mf_uid);
3321 3341
           continue;
3322 3342
         }
3323 3343
         
@@ -3353,7 +3373,7 @@ cmXsRC_t cmXScoreTest(
3353 3373
   // assign durations to pedal down events
3354 3374
   _cmXScoreProcessPedals(_cmXScoreHandleToPtr(h));
3355 3375
 
3356
-  // remove some notes which share a pitch which are overlapped or embedded
3376
+  // remove some notes which share a pitch and are overlapped or embedded within another note.
3357 3377
   _cmXScoreProcessOverlappingNotes(_cmXScoreHandleToPtr(h));
3358 3378
 
3359 3379
   if( csvOutFn != NULL )
@@ -3381,16 +3401,16 @@ cmXsRC_t cmXScoreTest(
3381 3401
   if( midiOutFn != NULL )
3382 3402
   {
3383 3403
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
3384
-    
3385
-    _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
3386 3404
 
3387 3405
     _cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
3406
+    
3407
+    _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
3388 3408
 
3389 3409
     cmFsFreePathParts(pp);
3390 3410
     
3391 3411
   }
3392 3412
   
3393
-  //cmXScoreReport(h,&ctx->rpt,true);
3413
+  cmXScoreReport(h,&ctx->rpt,true);
3394 3414
 
3395 3415
  errLabel:
3396 3416
   return cmXScoreFinalize(&h);

+ 2
- 1
app/cmXScore.h View File

@@ -19,7 +19,8 @@ extern "C" {
19 19
     kMidiFailXsRC,
20 20
     kFileFailXsRC,
21 21
     kSvgFailXsRC,
22
-    kOverlapWarnXsRC
22
+    kOverlapWarnXsRC,
23
+    kZeroLengthEventXsRC
23 24
   };
24 25
 
25 26
   typedef cmRC_t     cmXsRC_t;

Loading…
Cancel
Save