瀏覽代碼

cmMidiFile.h/c : Added cmMidiFileIsSustainPedal???() and cmMidiFileIsSostenutoPedal???().

Added new version of cmMidiFileCalcNodeDuration() which respects sostenuto pedal.
master
kevin 8 年之前
父節點
當前提交
2bc5274ef3
共有 2 個檔案被更改,包括 91 行新增45 行删除
  1. 85
    41
      cmMidiFile.c
  2. 6
    4
      cmMidiFile.h

+ 85
- 41
cmMidiFile.c 查看文件

@@ -11,6 +11,9 @@
11 11
 #include "cmMidi.h"
12 12
 #include "cmMidiFile.h"
13 13
 
14
+#include "cmFloatTypes.h"
15
+#include "cmVectOps.h"
16
+
14 17
 #ifdef cmBIG_ENDIAN
15 18
 #define mfSwap16(v)  (v)
16 19
 #define mfSwap32(v)  (v)
@@ -1194,7 +1197,7 @@ void  _cmMidiFileCalcNoteDurationsAllocVoice( _cmMidiVoice_t** listPtrPtr, cmMid
1194 1197
   *listPtrPtr   = vp;
1195 1198
 }
1196 1199
 
1197
-void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1200
+void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
1198 1201
 {
1199 1202
   _cmMidiFile_t* p;
1200 1203
 
@@ -1335,7 +1338,20 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1335 1338
   }
1336 1339
 }
1337 1340
 
1338
-void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
1341
+bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, bool noteGateFl, bool sustainGateFl, bool sostGateFl )
1342
+{
1343
+  // if the note is being kept sounding because the key is still depressed,
1344
+  //    the sustain pedal is down or it is being held by the sostenuto pedal ....
1345
+  if( noteGateFl || sustainGateFl || sostGateFl )
1346
+    return false;  // ... do nothing
1347
+
1348
+  // calculate the duration of the sounding note
1349
+  ((cmMidiChMsg_t*)m0->u.chMsgPtr)->durMicros = m1->amicro - m0->amicro;
1350
+  
1351
+  return true;
1352
+}
1353
+
1354
+void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1339 1355
 {
1340 1356
   _cmMidiFile_t* p;
1341 1357
 
@@ -1348,10 +1364,12 @@ void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
1348 1364
   unsigned          mi = cmInvalidId;
1349 1365
   cmMidiTrackMsg_t* noteM[     kMidiNoteCnt * kMidiChCnt ];  // ptr to note-on or NULL if the note is not sounding
1350 1366
   bool              noteGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note key is depressed
1351
-  bool              sustV[kMidiChCnt];                   //
1352
-  bool              sostV[kMidiChCnt];                   //
1367
+  bool              sostGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note was active when the sost. pedal went down
1368
+  bool              sustV[kMidiChCnt];                       // true if the associated sustain pedal is down
1369
+  bool              sostV[kMidiChCnt];                       // true if the associated sostenuto pedal is down
1353 1370
   unsigned          i,j;
1354
-  
1371
+
1372
+  // initialize the state tracking variables
1355 1373
   for(i=0; i<kMidiChCnt; ++i)
1356 1374
   {
1357 1375
     sustV[i] = false;
@@ -1360,106 +1378,132 @@ void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
1360 1378
     {
1361 1379
       noteM[     i*kMidiNoteCnt + j ] = NULL;
1362 1380
       noteGateM[ i*kMidiNoteCnt + j ] = false;
1381
+      sostGateM[ i*kMidiNoteCnt + j ] = false;
1363 1382
     }
1364 1383
   }
1365
-  
1384
+
1385
+  // for each midi event
1366 1386
   for(mi=0; mi<p->msgN; ++mi)
1367 1387
   {
1368 1388
     cmMidiTrackMsg_t* m = p->msgV[mi];
1369
-    
1389
+
1390
+    // verify that time is also incrementing
1370 1391
     assert(  mi==0 || (mi>0 &&  m->amicro >= p->msgV[mi-1]->amicro) );
1371 1392
 
1372 1393
     // ignore all non-channel messages
1373 1394
     if(  !cmMidiIsChStatus( m->status ) )
1374 1395
       continue;
1375 1396
 
1376
-    cmMidiByte_t ch = m->u.chMsgPtr->ch;
1377
-    cmMidiByte_t d0 = m->u.chMsgPtr->d0;
1378
-    cmMidiByte_t d1 = m->u.chMsgPtr->d1;
1379
-    
1397
+    cmMidiByte_t ch = m->u.chMsgPtr->ch; // get the midi msg channel
1398
+    cmMidiByte_t d0 = m->u.chMsgPtr->d0; // get the midi msg data value 
1399
+
1400
+    // if this is a note-on msg
1380 1401
     if( cmMidiFileIsNoteOn(m) )
1381 1402
     {
1382
-      unsigned            k = ch*kMidiNoteCnt + d0;
1383
-      cmMidiTrackMsg_t*  m0 = noteM[k];
1403
+      unsigned  k = ch*kMidiNoteCnt + d0;
1384 1404
       
1385 1405
       // a key was pressed - so it should not be currently down
1386 1406
       if( noteGateM[k] )
1387
-      {
1388
-        assert( m0 != NULL );
1389 1407
         cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-off for note-on:%s",cmMidiToSciPitch(d0,NULL,0));
1390
-      }
1391 1408
 
1392
-      noteM[k] = m;
1409
+      // there should be no existing sounding note instance for this pitch
1410
+      if( noteM[k] != NULL )
1411
+        cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-off instance for note on:%s",cmMidiToSciPitch(d0,NULL,0));
1412
+
1413
+      noteM[k]     = m;
1393 1414
       noteGateM[k] = true;
1394 1415
     }
1395 1416
     else
1417
+      
1418
+      // if this is a note-off msg
1396 1419
       if( cmMidiFileIsNoteOff(m) )
1397 1420
       {
1398 1421
         unsigned            k = ch*kMidiNoteCnt + d0;
1399 1422
         cmMidiTrackMsg_t*  m0 = noteM[k];
1400
-      
1401
-        // a key was released - so it should not be currently up
1402
-        if( noteGateM[k]==false )
1423
+
1424
+        if( m0 == NULL )
1425
+          cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-on instance for note-off:%s",cmMidiToSciPitch(d0,NULL,0));
1426
+        else
1403 1427
         {
1404
-          assert( m0 != NULL );
1405
-          cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-on for note-off:%s",cmMidiToSciPitch(d0,NULL,0));
1406
-        }
1428
+          // a key was released - so it should not already be up
1429
+          if( noteGateM[k]==false )
1430
+            cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-on for note-off:%s",cmMidiToSciPitch(d0,NULL,0));
1407 1431
 
1408
-        // FIX: release note here - if pedal is not down
1409
-        
1410
-        noteM[k] = NULL;
1411
-        noteGateM[k] = false;
1432
+          noteGateM[k] = false; // update the note gate state
1433
+
1434
+          // update the sounding note status
1435
+          if( _cmMidiFileCalcNoteDur(m0, m, noteGateM[k], sustV[ch], sostGateM[k]) )
1436
+            noteM[k] = NULL;
1437
+        }
1412 1438
       }
1413 1439
       else
1440
+        
1441
+        // This is a sustain-pedal down msg
1414 1442
         if( cmMidiFileIsSustainPedalDown(m) )
1415 1443
         {
1416 1444
           // if the sustain channel is already down
1417 1445
           if( sustV[ch] )
1418
-          {
1419 1446
             cmErrWarnMsg(&p->err,kSustainPedalMfRC,"The sustain pedal went down twice with no intervening release.");
1420
-          }
1421 1447
 
1422 1448
           sustV[ch] = true;          
1423 1449
         }
1424 1450
         else
1425
-          if( cmMidiFileIsSutainPedalUp(m) )
1451
+
1452
+          // This is a sustain-pedal up msg
1453
+          if( cmMidiFileIsSustainPedalUp(m) )
1426 1454
           {
1427 1455
             // if the sustain channel is already up
1428 1456
             if( sustV[ch]==false )
1429
-            {
1430 1457
               cmErrWarnMsg(&p->err,kSustainPedalMfRC,"The sustain pedal release message was received with no previous pedal down.");
1431
-            }
1432 1458
 
1433
-            // FIX: release sustaining notes here
1434 1459
             sustV[ch] = false;
1460
+
1461
+            unsigned k = ch*kMidiNoteCnt;
1462
+            
1463
+            // for each sounding note on this channel
1464
+            for(; k<ch*kMidiNoteCnt+kMidiNoteCnt; ++k)
1465
+              if( noteM[k]!=NULL && _cmMidiFileCalcNoteDur(noteM[k], m, noteGateM[k], sustV[ch], sostGateM[k]) )
1466
+                noteM[k] = NULL;
1467
+
1435 1468
           }
1436 1469
           else
1470
+
1471
+            // This is a sostenuto-pedal down msg
1437 1472
             if( cmMidiFileIsSostenutoPedalDown(m) )
1438 1473
             {
1439 1474
               // if the sustain channel is already down
1440 1475
               if( sostV[ch] )
1441
-              {
1442 1476
                 cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"The sostenuto pedal went down twice with no intervening release.");
1443
-              }
1444 1477
 
1478
+              // record the notes that are active when the sostenuto pedal went down
1479
+              unsigned k = ch * kMidiNoteCnt;
1480
+              cmVOB_Copy( sostGateM + k, kMidiNoteCnt, noteGateM + k);
1481
+              
1445 1482
               sostV[ch] = true;          
1446 1483
             }
1447 1484
             else
1485
+
1486
+              // This is a sostenuto-pedal up msg
1448 1487
               if( cmMidiFileIsSostenutoPedalUp(m) )
1449 1488
               {
1450 1489
                 // if the sustain channel is already up
1451 1490
                 if( sostV[ch]==false )
1452
-                {
1453 1491
                   cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"The sostenuto pedal release message was received with no previous pedal down.");
1454
-                }
1455 1492
 
1456
-                // FIX: release sostenuto notes here
1457 1493
                 sostV[ch] = false;
1494
+
1495
+                // for each note on this channel
1496
+                unsigned k = ch*kMidiNoteCnt;
1458 1497
                 
1498
+                for(; k<ch*kMidiNoteCnt+kMidiNoteCnt; ++k)
1499
+                {
1500
+                  sostGateM[k] = false;
1501
+                  if( noteM[k]!=NULL && _cmMidiFileCalcNoteDur(noteM[k], m, noteGateM[k], sustV[ch], sostGateM[k]) )
1502
+                    noteM[k] = NULL;
1503
+                }
1459 1504
               }
1460
-            
1461
-
1462
-  }
1505
+    
1506
+  } // for each midi file event
1463 1507
 }
1464 1508
 
1465 1509
 void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )

+ 6
- 4
cmMidiFile.h 查看文件

@@ -90,10 +90,12 @@ extern "C" {
90 90
 
91 91
 #define cmMidiFileIsNoteOn(m)         (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
92 92
 #define cmMidiFileIsNoteOff(m)        (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
93
-#define cmMidiFileIsSustainPedal(m)   (cmMidiIsSustainPedal((m)->status,(m)->u.chMsgPtr->d0))
94
-#define cmMidiFileIsSostenutoPedal(m) (cmMidiIsSostenutoPedal((m)->status,(m)->u.chMsgPtr->d0))
95
-#define cmMidiFileIsPedalDown(m)      (cmMidiIsPedalDown((m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1))
96
-#define cmMidiFileIsPedalUp(m)        (cmMidiIsPedalUp(  (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1))  
93
+  
94
+#define cmMidiFileIsSustainPedalUp(m)     (cmMidiIsSustainPedalUp(    (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
95
+#define cmMidiFileIsSustainPedalDown(m)   (cmMidiIsSustainPedalDown(  (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
96
+  
97
+#define cmMidiFileIsSostenutoPedalUp(m)   (cmMidiIsSostenutoPedalUp(  (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
98
+#define cmMidiFileIsSostenutoPedalDown(m) (cmMidiIsSostenutoPedalDown((m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
97 99
   
98 100
   enum
99 101
   {

Loading…
取消
儲存