Browse Source

cmMidiFile.h/c Added cmMIdiFileTickToSamples()

master
kevin 11 years ago
parent
commit
37c2599982
2 changed files with 189 additions and 161 deletions
  1. 24
    0
      cmMidiFile.c
  2. 165
    161
      cmMidiFile.h

+ 24
- 0
cmMidiFile.c View File

@@ -796,6 +796,30 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h )
796 796
   
797 797
 }
798 798
 
799
+void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl )
800
+{
801
+  _cmMidiFile_t* p;
802
+  unsigned mi;
803
+  //bool fl = true;
804
+
805
+  if((p = _cmMidiFileHandleToPtr(h)) == NULL )
806
+    return;
807
+
808
+  cmMidiFileTickToMicros(h);
809
+
810
+  unsigned absSmp = 0;
811
+
812
+  for(mi=0; mi<p->msgN; ++mi)
813
+  {
814
+    cmMidiTrackMsg_t* mp    = p->msgV[mi];
815
+    unsigned          delta = floor((mp->dtick*srate)/1000000.0);
816
+
817
+    mp->dtick  = absFl ? absSmp : delta;
818
+
819
+    absSmp    += delta;    
820
+  }
821
+}
822
+
799 823
 typedef struct _cmMidiVoice_str
800 824
 {
801 825
   const  cmMidiTrackMsg_t*  mp;

+ 165
- 161
cmMidiFile.h View File

@@ -5,168 +5,172 @@
5 5
 extern "C" {
6 6
 #endif
7 7
 
8
-// MIDI file timing:
9
-// Messages in the MIDI file are time tagged with a delta offset in 'ticks'
10
-// from the previous message in the same track.
11
-// 
12
-// A 'tick' can be converted to microsends as follows:
13
-//
14
-// microsecond per tick = micros per quarter note / ticks per quarter note
15
-// 
16
-// MpT = MpQN / TpQN
17
-// 
18
-// TpQN is given as a constant in the MIDI file header.
19
-// MpQN is given as the value of the MIDI file tempo message.
20
-//
21
-// See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds.
22
-//
23
-// As part of the file reading process, the status byte of note-on messages 
24
-// with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg().
25
-
26
-
27
-
28
-typedef cmHandle_t cmMidiFileH_t;
29
-typedef unsigned   cmMfRC_t;
30
-
31
-typedef struct
32
-{
33
-  cmMidiByte_t hr;
34
-  cmMidiByte_t min;
35
-  cmMidiByte_t sec;
36
-  cmMidiByte_t frm;
37
-  cmMidiByte_t sfr;
38
-} cmMidiSmpte_t;
39
-
40
-typedef struct
41
-{
42
-  cmMidiByte_t num;
43
-  cmMidiByte_t den;
44
-  cmMidiByte_t metro;
45
-  cmMidiByte_t th2s;
46
-} cmMidiTimeSig_t;
47
-
48
-typedef struct
49
-{
50
-  cmMidiByte_t key;
51
-  cmMidiByte_t scale;
52
-} cmMidiKeySig_t;
53
-
54
-typedef struct
55
-{
56
-  cmMidiByte_t ch;
57
-  cmMidiByte_t d0;
58
-  cmMidiByte_t d1;
59
-  unsigned     durTicks; // note duration calc'd by 
60
-} cmMidiChMsg_t;
61
-
62
-
63
-typedef struct cmMidiTrackMsg_str
64
-{
65
-  unsigned                   dtick;   // delta ticks
66
-  cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
67
-  cmMidiByte_t               metaId;  //
68
-  unsigned short             trkIdx;  //  
69
-  unsigned                   byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union)
70
-  struct cmMidiTrackMsg_str* link;    // link to next record in this track
71
-
72
-  union
8
+  // MIDI file timing:
9
+  // Messages in the MIDI file are time tagged with a delta offset in 'ticks'
10
+  // from the previous message in the same track.
11
+  // 
12
+  // A 'tick' can be converted to microsends as follows:
13
+  //
14
+  // microsecond per tick = micros per quarter note / ticks per quarter note
15
+  // 
16
+  // MpT = MpQN / TpQN
17
+  // 
18
+  // TpQN is given as a constant in the MIDI file header.
19
+  // MpQN is given as the value of the MIDI file tempo message.
20
+  //
21
+  // See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds.
22
+  //
23
+  // As part of the file reading process, the status byte of note-on messages 
24
+  // with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg().
25
+
26
+
27
+
28
+  typedef cmHandle_t cmMidiFileH_t;
29
+  typedef unsigned   cmMfRC_t;
30
+
31
+  typedef struct
73 32
   {
74
-    cmMidiByte_t           bVal;
75
-    unsigned               iVal;
76
-    unsigned short         sVal;
77
-    const char*            text;
78
-    const void*            voidPtr;
79
-    const cmMidiSmpte_t*   smptePtr;
80
-    const cmMidiTimeSig_t* timeSigPtr;
81
-    const cmMidiKeySig_t*  keySigPtr;
82
-    const cmMidiChMsg_t*   chMsgPtr;
83
-    const cmMidiByte_t*    sysExPtr;
84
-  } u;
85
-} cmMidiTrackMsg_t;
86
-
87
-enum
88
-{
89
-  kOkMfRC = cmOkRC,  // 0
90
-  kSysFopenFailMfRC,  // 1
91
-  kSysFreadFailMfRC,  // 2
92
-  kSysFseekFailMfRC,  // 3
93
-  kSysFtellFailMfRC,  // 4
94
-  kSysFcloseFailMfRC, // 5
95
-  kNotAMidiFileMfRC,  // 6
96
-  kMemAllocFailMfRC,  // 7
97
-  kFileCorruptMfRC,   // 8
98
-  kMissingEoxMfRC,    // 9 
99
-  kUnknownMetaIdMfRC, // 10
100
-  kInvalidHandleMfRC, // 11
101
-  kMissingNoteOffMfRC, // 12
102
-  kInvalidStatusMfRC  // 13
103
-};
104
-
105
-extern cmMidiFileH_t cmMidiFileNullHandle;
106
-
107
-cmMfRC_t              cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx );
108
-cmMfRC_t              cmMidiFileClose( cmMidiFileH_t* hp );
109
-
110
-// Returns track count or kInvalidCnt if 'h' is invalid.
111
-unsigned              cmMidiFileTrackCount( cmMidiFileH_t h );
112
-
113
-// Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
114
-unsigned              cmMidiFileType( cmMidiFileH_t h );
115
-
116
-// Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base.
117
-unsigned              cmMidiFileTicksPerQN( cmMidiFileH_t h );
118
-
119
-// The file name used in an earlier call to midiFileOpen() or NULL if this 
120
-// midi file did not originate from an actual file.
121
-const char*           cmMidiFileName( cmMidiFileH_t h );
122
-
123
-// Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
124
-cmMidiByte_t          cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
125
-
126
-// Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
127
-cmMidiByte_t          cmMidiFileSmpteFormatId( cmMidiFileH_t h );
128
-
129
-// Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
130
-unsigned              cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx );
131
-
132
-// Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
133
-const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
134
-
135
-// Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray().
136
-// Return kInvalidCnt if 'h' is invalid.
137
-unsigned              cmMidiFileMsgCount( cmMidiFileH_t h );
138
-
139
-// Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order.
140
-// Returns NULL if 'h' is invalid.
141
-const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
142
-
143
-// Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
144
-// msg exists after 'usecsOffs'.  Note that 'usecOffs' is an offset from the beginning
145
-// of the file.
146
-// On return *'msgUsecsPtr' is set to the actual time of the msg. 
147
-// (which will be equal to or greater than 'usecsOffs').
148
-unsigned              cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr );
149
-
150
-double                cmMidiFileDurSecs( cmMidiFileH_t h );
151
-
152
-// Convert the track message 'dtick' field to delta-microseconds.
153
-void                  cmMidiFileTickToMicros( cmMidiFileH_t h );
154
-
155
-// Calculate Note Duration 
156
-void                  cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
157
-
158
-// Set the delay prior to the first non-zero msg.
159
-void                  cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
160
-
161
-// This function packs a track msg into a single  consecutive 
162
-// block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount()
163
-// to get the required buffer length for any given cmMidiTrackMsg_t instance.
164
-cmMidiTrackMsg_t*     cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt );
165
-unsigned              cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m );
166
-
167
-void                  cmMidiFilePrint( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
168
-bool                  cmMidiFileIsNull( cmMidiFileH_t h );
169
-void                  cmMidiFileTest( const char* fn, cmCtx_t* ctx );
33
+    cmMidiByte_t hr;
34
+    cmMidiByte_t min;
35
+    cmMidiByte_t sec;
36
+    cmMidiByte_t frm;
37
+    cmMidiByte_t sfr;
38
+  } cmMidiSmpte_t;
39
+
40
+  typedef struct
41
+  {
42
+    cmMidiByte_t num;
43
+    cmMidiByte_t den;
44
+    cmMidiByte_t metro;
45
+    cmMidiByte_t th2s;
46
+  } cmMidiTimeSig_t;
47
+
48
+  typedef struct
49
+  {
50
+    cmMidiByte_t key;
51
+    cmMidiByte_t scale;
52
+  } cmMidiKeySig_t;
53
+
54
+  typedef struct
55
+  {
56
+    cmMidiByte_t ch;
57
+    cmMidiByte_t d0;
58
+    cmMidiByte_t d1;
59
+    unsigned     durTicks; // note duration calc'd by 
60
+  } cmMidiChMsg_t;
61
+
62
+
63
+  typedef struct cmMidiTrackMsg_str
64
+  {
65
+    unsigned                   dtick;   // delta ticks
66
+    cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
67
+    cmMidiByte_t               metaId;  //
68
+    unsigned short             trkIdx;  //  
69
+    unsigned                   byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union)
70
+    struct cmMidiTrackMsg_str* link;    // link to next record in this track
71
+
72
+    union
73
+    {
74
+      cmMidiByte_t           bVal;
75
+      unsigned               iVal;
76
+      unsigned short         sVal;
77
+      const char*            text;
78
+      const void*            voidPtr;
79
+      const cmMidiSmpte_t*   smptePtr;
80
+      const cmMidiTimeSig_t* timeSigPtr;
81
+      const cmMidiKeySig_t*  keySigPtr;
82
+      const cmMidiChMsg_t*   chMsgPtr;
83
+      const cmMidiByte_t*    sysExPtr;
84
+    } u;
85
+  } cmMidiTrackMsg_t;
86
+
87
+  enum
88
+  {
89
+    kOkMfRC = cmOkRC,  // 0
90
+    kSysFopenFailMfRC,  // 1
91
+    kSysFreadFailMfRC,  // 2
92
+    kSysFseekFailMfRC,  // 3
93
+    kSysFtellFailMfRC,  // 4
94
+    kSysFcloseFailMfRC, // 5
95
+    kNotAMidiFileMfRC,  // 6
96
+    kMemAllocFailMfRC,  // 7
97
+    kFileCorruptMfRC,   // 8
98
+    kMissingEoxMfRC,    // 9 
99
+    kUnknownMetaIdMfRC, // 10
100
+    kInvalidHandleMfRC, // 11
101
+    kMissingNoteOffMfRC, // 12
102
+    kInvalidStatusMfRC  // 13
103
+  };
104
+
105
+  extern cmMidiFileH_t cmMidiFileNullHandle;
106
+
107
+  cmMfRC_t              cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx );
108
+  cmMfRC_t              cmMidiFileClose( cmMidiFileH_t* hp );
109
+
110
+  // Returns track count or kInvalidCnt if 'h' is invalid.
111
+  unsigned              cmMidiFileTrackCount( cmMidiFileH_t h );
112
+
113
+  // Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
114
+  unsigned              cmMidiFileType( cmMidiFileH_t h );
115
+
116
+  // Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base.
117
+  unsigned              cmMidiFileTicksPerQN( cmMidiFileH_t h );
118
+
119
+  // The file name used in an earlier call to midiFileOpen() or NULL if this 
120
+  // midi file did not originate from an actual file.
121
+  const char*           cmMidiFileName( cmMidiFileH_t h );
122
+
123
+  // Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
124
+  cmMidiByte_t          cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
125
+
126
+  // Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
127
+  cmMidiByte_t          cmMidiFileSmpteFormatId( cmMidiFileH_t h );
128
+
129
+  // Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
130
+  unsigned              cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx );
131
+
132
+  // Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
133
+  const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
134
+
135
+  // Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray().
136
+  // Return kInvalidCnt if 'h' is invalid.
137
+  unsigned              cmMidiFileMsgCount( cmMidiFileH_t h );
138
+
139
+  // Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order.
140
+  // Returns NULL if 'h' is invalid.
141
+  const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
142
+
143
+  // Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
144
+  // msg exists after 'usecsOffs'.  Note that 'usecOffs' is an offset from the beginning
145
+  // of the file.
146
+  // On return *'msgUsecsPtr' is set to the actual time of the msg. 
147
+  // (which will be equal to or greater than 'usecsOffs').
148
+  unsigned              cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr );
149
+
150
+  double                cmMidiFileDurSecs( cmMidiFileH_t h );
151
+
152
+  // Convert the track message 'dtick' field to delta-microseconds.
153
+  void                  cmMidiFileTickToMicros( cmMidiFileH_t h );
154
+
155
+  // Convert the track message 'dtick' field to samples.
156
+  // If the absFl is set then the delta times are converted to absolute time.
157
+  void                  cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl );
158
+
159
+  // Calculate Note Duration 
160
+  void                  cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
161
+
162
+  // Set the delay prior to the first non-zero msg.
163
+  void                  cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
164
+
165
+  // This function packs a track msg into a single  consecutive 
166
+  // block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount()
167
+  // to get the required buffer length for any given cmMidiTrackMsg_t instance.
168
+  cmMidiTrackMsg_t*     cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt );
169
+  unsigned              cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m );
170
+
171
+  void                  cmMidiFilePrint( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
172
+  bool                  cmMidiFileIsNull( cmMidiFileH_t h );
173
+  void                  cmMidiFileTest( const char* fn, cmCtx_t* ctx );
170 174
 
171 175
 #ifdef __cplusplus
172 176
 }

Loading…
Cancel
Save