Browse Source

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

Added new version of cmMidiFileCalcNodeDuration() which respects sostenuto pedal.
master
kevin 8 years ago
parent
commit
2bc5274ef3
2 changed files with 91 additions and 45 deletions
  1. 85
    41
      cmMidiFile.c
  2. 6
    4
      cmMidiFile.h

+ 85
- 41
cmMidiFile.c View File

11
 #include "cmMidi.h"
11
 #include "cmMidi.h"
12
 #include "cmMidiFile.h"
12
 #include "cmMidiFile.h"
13
 
13
 
14
+#include "cmFloatTypes.h"
15
+#include "cmVectOps.h"
16
+
14
 #ifdef cmBIG_ENDIAN
17
 #ifdef cmBIG_ENDIAN
15
 #define mfSwap16(v)  (v)
18
 #define mfSwap16(v)  (v)
16
 #define mfSwap32(v)  (v)
19
 #define mfSwap32(v)  (v)
1194
   *listPtrPtr   = vp;
1197
   *listPtrPtr   = vp;
1195
 }
1198
 }
1196
 
1199
 
1197
-void cmMidiFileCalcNoteDurations( cmMidiFileH_t h )
1200
+void cmMidiFileCalcNoteDurations2( cmMidiFileH_t h )
1198
 {
1201
 {
1199
   _cmMidiFile_t* p;
1202
   _cmMidiFile_t* p;
1200
 
1203
 
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
   _cmMidiFile_t* p;
1356
   _cmMidiFile_t* p;
1341
 
1357
 
1348
   unsigned          mi = cmInvalidId;
1364
   unsigned          mi = cmInvalidId;
1349
   cmMidiTrackMsg_t* noteM[     kMidiNoteCnt * kMidiChCnt ];  // ptr to note-on or NULL if the note is not sounding
1365
   cmMidiTrackMsg_t* noteM[     kMidiNoteCnt * kMidiChCnt ];  // ptr to note-on or NULL if the note is not sounding
1350
   bool              noteGateM[ kMidiNoteCnt * kMidiChCnt ];  // true if the associated note key is depressed
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
   unsigned          i,j;
1370
   unsigned          i,j;
1354
-  
1371
+
1372
+  // initialize the state tracking variables
1355
   for(i=0; i<kMidiChCnt; ++i)
1373
   for(i=0; i<kMidiChCnt; ++i)
1356
   {
1374
   {
1357
     sustV[i] = false;
1375
     sustV[i] = false;
1360
     {
1378
     {
1361
       noteM[     i*kMidiNoteCnt + j ] = NULL;
1379
       noteM[     i*kMidiNoteCnt + j ] = NULL;
1362
       noteGateM[ i*kMidiNoteCnt + j ] = false;
1380
       noteGateM[ i*kMidiNoteCnt + j ] = false;
1381
+      sostGateM[ i*kMidiNoteCnt + j ] = false;
1363
     }
1382
     }
1364
   }
1383
   }
1365
-  
1384
+
1385
+  // for each midi event
1366
   for(mi=0; mi<p->msgN; ++mi)
1386
   for(mi=0; mi<p->msgN; ++mi)
1367
   {
1387
   {
1368
     cmMidiTrackMsg_t* m = p->msgV[mi];
1388
     cmMidiTrackMsg_t* m = p->msgV[mi];
1369
-    
1389
+
1390
+    // verify that time is also incrementing
1370
     assert(  mi==0 || (mi>0 &&  m->amicro >= p->msgV[mi-1]->amicro) );
1391
     assert(  mi==0 || (mi>0 &&  m->amicro >= p->msgV[mi-1]->amicro) );
1371
 
1392
 
1372
     // ignore all non-channel messages
1393
     // ignore all non-channel messages
1373
     if(  !cmMidiIsChStatus( m->status ) )
1394
     if(  !cmMidiIsChStatus( m->status ) )
1374
       continue;
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
     if( cmMidiFileIsNoteOn(m) )
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
       // a key was pressed - so it should not be currently down
1405
       // a key was pressed - so it should not be currently down
1386
       if( noteGateM[k] )
1406
       if( noteGateM[k] )
1387
-      {
1388
-        assert( m0 != NULL );
1389
         cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"Missing note-off for note-on:%s",cmMidiToSciPitch(d0,NULL,0));
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
       noteGateM[k] = true;
1414
       noteGateM[k] = true;
1394
     }
1415
     }
1395
     else
1416
     else
1417
+      
1418
+      // if this is a note-off msg
1396
       if( cmMidiFileIsNoteOff(m) )
1419
       if( cmMidiFileIsNoteOff(m) )
1397
       {
1420
       {
1398
         unsigned            k = ch*kMidiNoteCnt + d0;
1421
         unsigned            k = ch*kMidiNoteCnt + d0;
1399
         cmMidiTrackMsg_t*  m0 = noteM[k];
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
       else
1439
       else
1440
+        
1441
+        // This is a sustain-pedal down msg
1414
         if( cmMidiFileIsSustainPedalDown(m) )
1442
         if( cmMidiFileIsSustainPedalDown(m) )
1415
         {
1443
         {
1416
           // if the sustain channel is already down
1444
           // if the sustain channel is already down
1417
           if( sustV[ch] )
1445
           if( sustV[ch] )
1418
-          {
1419
             cmErrWarnMsg(&p->err,kSustainPedalMfRC,"The sustain pedal went down twice with no intervening release.");
1446
             cmErrWarnMsg(&p->err,kSustainPedalMfRC,"The sustain pedal went down twice with no intervening release.");
1420
-          }
1421
 
1447
 
1422
           sustV[ch] = true;          
1448
           sustV[ch] = true;          
1423
         }
1449
         }
1424
         else
1450
         else
1425
-          if( cmMidiFileIsSutainPedalUp(m) )
1451
+
1452
+          // This is a sustain-pedal up msg
1453
+          if( cmMidiFileIsSustainPedalUp(m) )
1426
           {
1454
           {
1427
             // if the sustain channel is already up
1455
             // if the sustain channel is already up
1428
             if( sustV[ch]==false )
1456
             if( sustV[ch]==false )
1429
-            {
1430
               cmErrWarnMsg(&p->err,kSustainPedalMfRC,"The sustain pedal release message was received with no previous pedal down.");
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
             sustV[ch] = false;
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
           else
1469
           else
1470
+
1471
+            // This is a sostenuto-pedal down msg
1437
             if( cmMidiFileIsSostenutoPedalDown(m) )
1472
             if( cmMidiFileIsSostenutoPedalDown(m) )
1438
             {
1473
             {
1439
               // if the sustain channel is already down
1474
               // if the sustain channel is already down
1440
               if( sostV[ch] )
1475
               if( sostV[ch] )
1441
-              {
1442
                 cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"The sostenuto pedal went down twice with no intervening release.");
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
               sostV[ch] = true;          
1482
               sostV[ch] = true;          
1446
             }
1483
             }
1447
             else
1484
             else
1485
+
1486
+              // This is a sostenuto-pedal up msg
1448
               if( cmMidiFileIsSostenutoPedalUp(m) )
1487
               if( cmMidiFileIsSostenutoPedalUp(m) )
1449
               {
1488
               {
1450
                 // if the sustain channel is already up
1489
                 // if the sustain channel is already up
1451
                 if( sostV[ch]==false )
1490
                 if( sostV[ch]==false )
1452
-                {
1453
                   cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"The sostenuto pedal release message was received with no previous pedal down.");
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
                 sostV[ch] = false;
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
 void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )
1509
 void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks )

+ 6
- 4
cmMidiFile.h View File

90
 
90
 
91
 #define cmMidiFileIsNoteOn(m)         (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
91
 #define cmMidiFileIsNoteOn(m)         (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
92
 #define cmMidiFileIsNoteOff(m)        (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
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
   enum
100
   enum
99
   {
101
   {

Loading…
Cancel
Save