Browse Source

Merge branch 'master' of klarke.webfactional.com:webapps/git/repos/libcm

master
kevin 11 years ago
parent
commit
a3ce46c35b
11 changed files with 721 additions and 199 deletions
  1. 17
    11
      app/cmTimeLine.c
  2. 9
    0
      app/cmTimeLine.h
  3. 22
    6
      cmGrPlot.c
  4. 24
    0
      cmMidiFile.c
  5. 165
    161
      cmMidiFile.h
  6. 1
    2
      dsp/cmDspBuiltIn.c
  7. 1
    1
      dsp/cmDspClass.h
  8. 436
    10
      dsp/cmDspKr.c
  9. 1
    0
      dsp/cmDspKr.h
  10. 40
    3
      dsp/cmDspPgmKr.c
  11. 5
    5
      dsp/cmDspUi.c

+ 17
- 11
app/cmTimeLine.c View File

@@ -635,9 +635,9 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
635 635
   unsigned                 mn           = cmMidiFileMsgCount(mfH);
636 636
   const cmMidiTrackMsg_t** mapp         = cmMidiFileMsgArray(mfH);
637 637
   unsigned                 mi           = 0;
638
-  double                   accum = 0; 
638
+  //double                   accum = 0; 
639 639
   _cmTlObj_t*              refOp        = op;
640
-  bool                     fl           = false;
640
+  //bool                     fl           = false;
641 641
   unsigned                 dtick        = 0;
642 642
   mfp->noteOnCnt = 0;
643 643
   
@@ -649,16 +649,16 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
649 649
 
650 650
     dtick = mp->dtick;
651 651
 
652
-    if( fl )
653
-    {
654
-      dtick = 0;
655
-      fl =  mp->dtick == 0;        
656
-    }
652
+    //if( fl )
653
+    //{
654
+    //  dtick = 0;
655
+    //  fl =  mp->dtick == 0;        
656
+    //}
657 657
       
658
-    accum += dtick * p->srate / 1000000;
658
+    //accum += dtick * p->srate / 1000000;
659 659
 
660 660
     //int      begSmpIdx         = floor(accum_micros * p->srate / 1000000);
661
-    int      begSmpIdx         = floor( dtick * p->srate / 1000000 );
661
+    int      begSmpIdx         = dtick; //floor( dtick * p->srate / 1000000.0 );
662 662
     int      durSmpCnt         = 0;
663 663
     unsigned midiTrkMsgByteCnt = cmMidiFilePackTrackMsgBufByteCount( mp );
664 664
     unsigned recdByteCnt       = sizeof(cmTlMidiEvt_t) + midiTrkMsgByteCnt;
@@ -669,7 +669,8 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
669 669
     // count the note-on messages
670 670
     if( mp->status == kNoteOnMdId )
671 671
     {
672
-      durSmpCnt = floor(mp->u.chMsgPtr->durTicks * p->srate  / 1000000 );
672
+      //durSmpCnt = floor(mp->u.chMsgPtr->durTicks * p->srate  / 1000000.0 );
673
+      durSmpCnt = mp->u.chMsgPtr->durTicks;
673 674
       ++mfp->noteOnCnt;
674 675
     }
675 676
 
@@ -727,7 +728,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
727 728
   unsigned durSmpCnt = floor(cmMidiFileDurSecs(mfH)*p->srate);
728 729
 
729 730
   // convert the midi file from ticks to microseconds
730
-  cmMidiFileTickToMicros(mfH);
731
+  cmMidiFileTickToSamples(mfH,p->srate,false);
731 732
 
732 733
   // assign note durations to all note-on msg's
733 734
   cmMidiFileCalcNoteDurations(mfH);
@@ -957,6 +958,11 @@ double cmTimeLineSampleRate( cmTlH_t h )
957 958
   return p->srate;
958 959
 }
959 960
 
961
+int cmTimeLineSeqToLocalSampleIndex( int seqSmpIdx, cmTlObj_t* localObjPtr )
962
+{
963
+  return seqSmpIdx - localObjPtr->seqSmpIdx;
964
+}
965
+
960 966
 cmTlObj_t* _cmTimeLineIdToObj( _cmTl_t* p, unsigned seqId, unsigned id )
961 967
 {
962 968
   assert( seqId < p->seqCnt );

+ 9
- 0
app/cmTimeLine.h View File

@@ -111,6 +111,9 @@ extern "C" {
111 111
   bool            cmTimeLineIsValid( cmTlH_t h );
112 112
   double          cmTimeLineSampleRate( cmTlH_t h );
113 113
 
114
+  // Convert global (sequence) time to a time relative to an object.
115
+  int             cmTimeLineSeqToLocalSampleIndex( int seqSmpIdx, cmTlObj_t* localObjPtr );
116
+
114 117
   // Given cmTlObj_t.uid return a pointer to the associated record.
115 118
   // seqId is optional (dflt:cmInvalidId)
116 119
   cmTlObj_t*      cmTimeLineIdToObj( cmTlH_t h, unsigned seqId, unsigned uid );
@@ -157,6 +160,12 @@ extern "C" {
157 160
   cmTlMidiEvt_t*   cmTimeLineMidiEvtAtTime(   cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
158 161
   cmTlMarker_t*    cmTimeLineMarkerAtTime(    cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
159 162
 
163
+
164
+  cmTlAudioFile_t* cmTimeLineAudioFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
165
+  cmTlMidiFile_t*  cmTimeLineMidiFileAtTime(  cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
166
+  cmTlMidiEvt_t*   cmTimeLineMidiEvtAtTime(   cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
167
+  cmTlMarker_t*    cmTimeLineMarkerAtTime(    cmTlH_t h, unsigned seqId, unsigned seqSmpIdx );
168
+
160 169
   // 'typeId' = kAudioFileTlId, kMidiFileTId, kMarkerTlId.
161 170
   // 'nameStr' and 'refObjNameStr' may be NULL.
162 171
   cmTlRC_t cmTimeLineInsert( 

+ 22
- 6
cmGrPlot.c View File

@@ -217,22 +217,32 @@ void _cmGrPlotObjSetFocus( cmGrPlotObj_t* op )
217 217
     if( cmIsNotFlag(op->cfgFlags,kNoFocusGrPlFl) && cmIsNotFlag(op->cfgFlags,kNoDrawGrPlFl) )
218 218
       break;
219 219
 
220
-  if( op != NULL )
220
+  // if the focus is changing to a new object
221
+  if( op != NULL  && op->p->fop != op )
221 222
   {  
222 223
     if( op->p->fop != NULL )
223 224
     {
224 225
       // if the application callback returns false then do no release focus from the current object
225
-      if(_cmGrPlotObjCb(op->p->fop, kStateChangeGrPlId, kFocusGrPlFl ) == false )
226
+      if(_cmGrPlotObjCb(op->p->fop, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false )
226 227
         return;
227 228
 
229
+      cmGrPlotObj_t* fop = op->p->fop;
230
+
228 231
       op->p->fop = NULL;
232
+
233
+      // notify focus loser
234
+      _cmGrPlotObjCb(fop, kStateChangeGrPlId, kFocusGrPlFl );
229 235
     }
230 236
 
231 237
     // if the application callback returns false then do not give focus to the selected object
232
-    if(_cmGrPlotObjCb(op, kStateChangeGrPlId, kFocusGrPlFl ) == false )
238
+    if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false )
233 239
       return;
234 240
 
235 241
     op->p->fop = op;
242
+
243
+    // notify focus winner
244
+    _cmGrPlotObjCb(op, kStateChangeGrPlId, kFocusGrPlFl );
245
+        
236 246
   }
237 247
 
238 248
 }
@@ -246,7 +256,7 @@ void _cmGrPlotObjSetSelect( cmGrPlotObj_t* op, bool clearFl )
246 256
   unsigned stateFlags = op->stateFlags;
247 257
 
248 258
   // if the application callback returns false then do change the select state of the object
249
-  if(_cmGrPlotObjCb(op, kStateChangeGrPlId, kSelectGrPlFl ) == false )
259
+  if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kSelectGrPlFl ) == false )
250 260
     return;
251 261
 
252 262
   if( clearFl )
@@ -262,6 +272,8 @@ void _cmGrPlotObjSetSelect( cmGrPlotObj_t* op, bool clearFl )
262 272
          
263 273
   op->stateFlags = cmTogFlag(stateFlags,kSelectGrPlFl);
264 274
 
275
+  // notify state change
276
+  _cmGrPlotObjCb(op, kStateChangeGrPlId, kSelectGrPlFl );
265 277
 }
266 278
 
267 279
 
@@ -914,18 +926,22 @@ void       cmGrPlotObjSetStateFlags( cmGrPlObjH_t oh, unsigned flags )
914 926
 
915 927
   if( cmIsFlag(flags,kVisibleGrPlFl) != _cmGrPlotObjIsVisible(op) )
916 928
   {
917
-    if( _cmGrPlotObjCb(op, kStateChangeGrPlId, kVisibleGrPlFl ) == false )
929
+    if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kVisibleGrPlFl ) == false )
918 930
       return;
919 931
 
920 932
     op->cfgFlags = cmTogFlag(op->cfgFlags,kNoDrawGrPlFl);
933
+
934
+    _cmGrPlotObjCb(op, kStateChangeGrPlId, kVisibleGrPlFl );
921 935
   }
922 936
 
923 937
   if( cmIsFlag(flags,kEnabledGrPlFl) != _cmGrPlotObjIsEnabled(op) )
924 938
   {
925
-    if( _cmGrPlotObjCb(op, kStateChangeGrPlId, kEnabledGrPlFl ) == false )
939
+    if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kEnabledGrPlFl ) == false )
926 940
       return;
927 941
 
928 942
     op->stateFlags = cmTogFlag(op->cfgFlags,kEnabledGrPlFl);
943
+
944
+    _cmGrPlotObjCb(op, kStateChangeGrPlId, kEnabledGrPlFl );        
929 945
   }
930 946
 
931 947
   bool fl;

+ 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
 }

+ 1
- 2
dsp/cmDspBuiltIn.c View File

@@ -1534,8 +1534,6 @@ cmDspInst_t*  _cmDspTextAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned
1534 1534
 
1535 1535
   cmDspText_t* p = cmDspInstAlloc(cmDspText_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
1536 1536
 
1537
-  
1538
-
1539 1537
   // create the UI control
1540 1538
   cmDspUiTextCreate(ctx,&p->inst,kValTxId,kLblTxId);
1541 1539
 
@@ -4993,6 +4991,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] =
4993 4991
   cmSegLineClassCons,
4994 4992
   
4995 4993
   cmTimeLineClassCons,
4994
+  cmMidiFilePlayClassCons,
4996 4995
   
4997 4996
   NULL,
4998 4997
 };

+ 1
- 1
dsp/cmDspClass.h View File

@@ -392,7 +392,7 @@ extern "C" {
392 392
   cmDspRC_t  cmDspUiMeterCreate(  cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned minVarId,  unsigned maxVarId,  unsigned valVarId,  unsigned lblVarId );
393 393
   cmDspRC_t  cmDspUiButtonCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned typeDuiId, unsigned outVarId, unsigned lblVarId );
394 394
   cmDspRC_t  cmDspUiLabelCreate(  cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned lblVarId,  unsigned alignVarId );
395
-  cmDspRC_t  cmDspUiTimeLineCreate(cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned valVarId,  unsigned lblVarId, unsigned tlFileId, unsigned audPathId );
395
+  cmDspRC_t  cmDspUiTimeLineCreate(cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned tlFileVarId,  unsigned audPathVarId, unsigned selVarId );
396 396
 
397 397
   cmDspRC_t  cmDspUiNewColumn(        cmDspCtx_t* ctx, unsigned colW );
398 398
   cmDspRC_t  cmDspUiInsertHorzBorder( cmDspCtx_t* ctx );

+ 436
- 10
dsp/cmDspKr.c View File

@@ -24,6 +24,7 @@
24 24
 #include "cmOp.h"
25 25
 #include "cmMath.h"
26 26
 
27
+
27 28
 #include "cmAudioFile.h"
28 29
 #include "cmFileSys.h"
29 30
 #include "cmProcObj.h"
@@ -33,6 +34,12 @@
33 34
 #include "cmProc2.h"
34 35
 #include "cmVectOpsTemplateMain.h"
35 36
 
37
+#include "cmAudioFile.h"
38
+#include "cmMidiFile.h"
39
+#include "cmTimeLine.h"
40
+#include "cmScore.h"
41
+#include "cmProc4.h"
42
+
36 43
 enum
37 44
 {
38 45
   kWndSmpCntKrId,
@@ -227,12 +234,20 @@ struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx )
227 234
 
228 235
 
229 236
 //==========================================================================================================================================
237
+// Time Line UI Object
238
+
230 239
 enum
231 240
 {
232
-  kValTlId,
233
-  kLblTlId,
234 241
   kTlFileTlId,
235
-  kAudPathTlId
242
+  kAudPathTlId,
243
+  kSelTlId,
244
+  kAudFnTlId,
245
+  kMidiFnTlId,
246
+  kBegAudSmpIdxTlId,
247
+  kEndAudSmpIdxTlId,
248
+  kBegMidiSmpIdxTlId,
249
+  kEndMidiSmpIdxTlId
250
+
236 251
 };
237 252
 
238 253
 cmDspClass_t _cmTimeLineDC;
@@ -240,38 +255,113 @@ cmDspClass_t _cmTimeLineDC;
240 255
 typedef struct
241 256
 {
242 257
   cmDspInst_t inst;
258
+  cmTlH_t     tlH;
243 259
 } cmDspTimeLine_t;
244 260
 
245 261
 cmDspInst_t*  _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
246 262
 {
247 263
   cmDspVarArg_t args[] =
248 264
   {
249
-    { "val",  kValTlId,  0, 0, kInDsvFl  | kOutDsvFl    | kStrzDsvFl | kReqArgDsvFl | kSendDfltDsvFl,  "Current string"},
250
-    { "lbl",  kLblTlId,  0, 0, kStrzDsvFl | kOptArgDsvFl, "Label"},
265
+    { "tlfile",  kTlFileTlId,         0, 0, kInDsvFl   | kStrzDsvFl | kReqArgDsvFl,   "Time line file." },
266
+    { "path",    kAudPathTlId,        0, 0, kInDsvFl   | kStrzDsvFl | kReqArgDsvFl,   "Audio path"    },
267
+    { "sel",     kSelTlId,            0, 0, kInDsvFl   | kInDsvFl   | kOutDsvFl  | kUIntDsvFl,   "Selected marker id."},
268
+    { "afn",     kAudFnTlId,          0, 0, kOutDsvFl  | kStrzDsvFl,   "Selected Audio file." },
269
+    { "mfn",     kMidiFnTlId,         0, 0, kOutDsvFl  | kStrzDsvFl,   "Selected MIDI file." },
270
+    { "absi",     kBegAudSmpIdxTlId,  0, 0, kOutDsvFl  | kIntDsvFl,   "Begin audio sample index."},
271
+    { "aesi",     kEndAudSmpIdxTlId,  0, 0, kOutDsvFl  | kIntDsvFl,   "End audio sample index."},
272
+    { "mbsi",     kBegMidiSmpIdxTlId, 0, 0, kOutDsvFl  | kIntDsvFl,   "Begin MIDI sample index."},
273
+    { "mesi",     kEndMidiSmpIdxTlId, 0, 0, kOutDsvFl  | kIntDsvFl,   "End MIDI sample index."},
251 274
     { NULL, 0, 0, 0, 0 }
252 275
   };
253 276
 
254 277
   cmDspTimeLine_t* p = cmDspInstAlloc(cmDspTimeLine_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
278
+  
279
+  cmDspSetDefaultUInt( ctx, &p->inst,  kSelTlId,           0, cmInvalidId);
280
+  cmDspSetDefaultStrcz(ctx, &p->inst,  kAudFnTlId,         NULL, "");
281
+  cmDspSetDefaultStrcz(ctx, &p->inst,  kMidiFnTlId,        NULL, "");
282
+  cmDspSetDefaultInt(  ctx, &p->inst,  kBegAudSmpIdxTlId,  0, cmInvalidIdx);
283
+  cmDspSetDefaultInt(  ctx, &p->inst,  kEndAudSmpIdxTlId,  0, cmInvalidIdx);
284
+  cmDspSetDefaultInt(  ctx, &p->inst,  kBegMidiSmpIdxTlId, 0, cmInvalidIdx);
285
+  cmDspSetDefaultInt(  ctx, &p->inst,  kEndMidiSmpIdxTlId, 0, cmInvalidIdx);
255 286
 
256 287
   // create the UI control
257
-  cmDspUiTimeLineCreate(ctx,&p->inst,kValTlId,kLblTlId,kTlFileTlId,kAudPathTlId);
288
+  cmDspUiTimeLineCreate(ctx,&p->inst,kTlFileTlId,kAudPathTlId,kSelTlId);
289
+
290
+  p->tlH = cmTimeLineNullHandle;
258 291
 
259 292
   return &p->inst;
260 293
 }
261 294
 
295
+cmDspRC_t _cmDspTimeLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
296
+{
297
+  cmDspRC_t        rc = kOkDspRC;
298
+  cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst;
299
+
300
+  if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
301
+    return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Time-line finalize failed.");
302
+
303
+  return rc;
304
+}
305
+
306
+
262 307
 cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
263 308
 {
309
+  cmDspRC_t        rc = kOkDspRC;
310
+  cmDspTimeLine_t* p  = (cmDspTimeLine_t*)inst;
311
+
264 312
   cmDspApplyAllDefaults(ctx,inst);
265
-  return kOkDspRC;
313
+
314
+  const cmChar_t* tlFn;
315
+  if((tlFn =  cmDspStrcz(inst, kTlFileTlId )) !=  NULL )
316
+    if( cmTimeLineInitializeFromFile(ctx->cmCtx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC )
317
+      rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Time-line file open failed.");
318
+
319
+  return rc;
266 320
 }
267 321
 
268 322
 cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
269 323
 {
324
+  cmDspTimeLine_t* p  = (cmDspTimeLine_t*)inst;
270 325
 
271 326
   switch( evt->dstVarId )
272 327
   {
273
-    case kValTlId:
274
-      cmDspSetEvent(ctx,inst,evt);
328
+    case kSelTlId:
329
+      {
330
+        unsigned markerId;
331
+        cmDspSetEvent(ctx,inst,evt);
332
+        
333
+        // get the id of the selected marker
334
+        if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId )
335
+        {
336
+          // get the marker object
337
+          cmTlObj_t* op;
338
+          if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
339
+          {
340
+            assert(op->typeId == kMarkerTlId);
341
+
342
+            cmDspSetInt(ctx, inst, kBegAudSmpIdxTlId,  op->begSmpIdx );
343
+            cmDspSetInt(ctx, inst, kEndAudSmpIdxTlId,  op->begSmpIdx + op->durSmpCnt );
344
+            
345
+            // locate the audio file assoc'd with the marker
346
+            cmTlAudioFile_t* afp;
347
+            if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL)
348
+              cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn );
349
+
350
+            // locate the midi file assoc'd with the marker
351
+            cmTlMidiFile_t* mfp;
352
+            if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL )
353
+            {
354
+              cmDspSetInt(ctx, inst, kBegMidiSmpIdxTlId, op->seqSmpIdx - mfp->obj.seqSmpIdx );
355
+              cmDspSetInt(ctx, inst, kEndMidiSmpIdxTlId, op->seqSmpIdx + op->durSmpCnt - mfp->obj.seqSmpIdx );
356
+
357
+              cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn );
358
+            }
359
+          }
360
+          
361
+        }
362
+        
363
+      }
364
+      
275 365
       break;
276 366
 
277 367
     default:
@@ -286,7 +376,7 @@ struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
286 376
   cmDspClassSetup(&_cmTimeLineDC,ctx,"TimeLine",
287 377
     NULL,
288 378
     _cmDspTimeLineAlloc,
289
-    NULL,
379
+    _cmDspTimeLineFree,
290 380
     _cmDspTimeLineReset,
291 381
     NULL,
292 382
     _cmDspTimeLineRecv,
@@ -296,3 +386,339 @@ struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx )
296 386
   return &_cmTimeLineDC;
297 387
 }
298 388
 
389
+//==========================================================================================================================================
390
+// MIDI File Player
391
+
392
+enum
393
+{
394
+  kFnMfId,
395
+  kSelMfId,    
396
+  kBsiMfId,
397
+  kEsiMfId,
398
+  kStatusMfId,
399
+  kD0MfId,
400
+  kD1MfId
401
+};
402
+
403
+cmDspClass_t _cmMidiFilePlayDC;
404
+
405
+typedef struct
406
+{
407
+  cmDspInst_t   inst;
408
+  cmMidiFileH_t mfH;  
409
+  unsigned      curMsgIdx;     // current midi file msg index
410
+  int           csi;           // current sample index
411
+  int           bsi;           // starting sample index
412
+  int           esi;           // ending sample index
413
+  unsigned      startSymId;
414
+  unsigned      stopSymId;
415
+  unsigned      contSymId;
416
+} cmDspMidiFilePlay_t;
417
+
418
+/*
419
+  'bsi' and 'esi' give the starting and ending sample for MIDI file playback.
420
+  These indexes are relative to the start of the file.
421
+  When the player recieves a 'start' msg it sets the current sample index
422
+  'si' to 'bsi' and begins scanning for the next note to play.  
423
+  On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval
424
+  si:si+sPc-1 will be transmitted.  (where sPc are the number of samples per DSP cycle).
425
+ */
426
+
427
+cmDspInst_t*  _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
428
+{
429
+  cmDspVarArg_t args[] =
430
+  {
431
+    { "fn",     kFnMfId,     0, 0, kInDsvFl  | kStrzDsvFl, "File name"},
432
+    { "sel",    kSelMfId,    0, 0, kInDsvFl  | kSymDsvFl,  "start | stop | continue" },
433
+    { "bsi",    kBsiMfId,    0, 0, kInDsvFl  | kIntDsvFl, "Starting sample." },
434
+    { "esi",    kEsiMfId,    0, 0, kInDsvFl  | kIntDsvFl, "Ending sample."},
435
+    { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" },
436
+    { "d0",     kD0MfId,     0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" },
437
+    { "d1",     kD1MfId,     0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" },
438
+    { NULL, 0, 0, 0, 0 }
439
+  };
440
+
441
+  cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
442
+
443
+  p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
444
+  p->stopSymId  = cmSymTblRegisterStaticSymbol(ctx->stH,"stop");
445
+  p->contSymId  = cmSymTblRegisterStaticSymbol(ctx->stH,"continue");
446
+  p->mfH        = cmMidiFileNullHandle;
447
+
448
+  cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId,   NULL, "");
449
+  cmDspSetDefaultSymbol(ctx, &p->inst,  kSelMfId,    p->stopSymId);
450
+  cmDspSetDefaultInt(   ctx, &p->inst,  kBsiMfId,    0, 0);
451
+  cmDspSetDefaultInt(   ctx, &p->inst,  kEsiMfId,    0, 0);
452
+  cmDspSetDefaultUInt(  ctx, &p->inst,  kStatusMfId, 0, 0);
453
+  cmDspSetDefaultUInt(  ctx, &p->inst,  kD0MfId,     0, 0);
454
+  cmDspSetDefaultUInt(  ctx, &p->inst,  kD1MfId,     0, 0);
455
+
456
+  return &p->inst;
457
+}
458
+
459
+cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
460
+{
461
+  cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
462
+  if( cmMidiFileClose(&p->mfH) )
463
+    return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed.");
464
+  return kOkDspRC;
465
+}
466
+
467
+// return the index of the msg following smpIdx
468
+unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspMidiFilePlay_t* p, unsigned smpIdx )
469
+{
470
+  unsigned                 i;
471
+  unsigned                 n     = cmMidiFileMsgCount(p->mfH);
472
+  const cmMidiTrackMsg_t** a     = cmMidiFileMsgArray(p->mfH);
473
+
474
+  for(i=0; i<n; ++i)
475
+    if( a[i]->dtick > smpIdx )
476
+      break;
477
+
478
+  return i==n ? cmInvalidIdx : i;
479
+}
480
+
481
+cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst )
482
+{
483
+  cmDspRC_t            rc = kOkDspRC;
484
+  const cmChar_t*      fn = cmDspStrcz(inst,kFnMfId);
485
+  cmDspMidiFilePlay_t* p  = (cmDspMidiFilePlay_t*)inst;
486
+
487
+  if( fn==NULL || strlen(fn)==0 )
488
+    return rc;
489
+
490
+  if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC )
491
+    rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed.");
492
+  else
493
+  {
494
+    p->curMsgIdx = 0;
495
+    p->bsi       = cmDspInt(inst,kBsiMfId);
496
+    p->esi       = cmDspInt(inst,kEsiMfId);
497
+    p->csi       = 0;
498
+
499
+    // force the first msg to occurr one quarter note into the file
500
+    cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) );
501
+
502
+    // convert midi msg times to absolute time in samples
503
+    cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true);
504
+  }
505
+  return rc;
506
+}
507
+
508
+cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
509
+{
510
+  cmDspApplyAllDefaults(ctx,inst);
511
+
512
+  return _cmDspMidiFilePlayOpen(ctx,inst);
513
+}
514
+
515
+cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
516
+{
517
+  cmDspRC_t            rc  = kOkDspRC;
518
+  cmDspMidiFilePlay_t* p   = (cmDspMidiFilePlay_t*)inst;
519
+  unsigned             sPc = cmDspSamplesPerCycle(ctx);
520
+
521
+  if( cmDspSymbol(inst,kSelMfId) != p->stopSymId )
522
+  {
523
+    const cmMidiTrackMsg_t** mpp   = cmMidiFileMsgArray(p->mfH);
524
+    unsigned                 msgN  = cmMidiFileMsgCount(p->mfH);
525
+  
526
+    for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick  &&  mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx )
527
+    {
528
+      const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx];
529
+      switch( mp->status )
530
+      {
531
+        case kNoteOnMdId:
532
+        case kCtlMdId:
533
+          cmDspSetUInt(ctx,inst, kD1MfId,     mp->u.chMsgPtr->d1);
534
+          cmDspSetUInt(ctx,inst, kD0MfId,     mp->u.chMsgPtr->d0);
535
+          cmDspSetUInt(ctx,inst, kStatusMfId, mp->status);
536
+          break;
537
+      }
538
+    }
539
+  }
540
+
541
+  p->csi += sPc;
542
+  
543
+  return rc;
544
+}
545
+
546
+cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
547
+{ 
548
+  cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst;
549
+  
550
+  cmDspSetEvent(ctx,inst,evt);
551
+
552
+  switch(evt->dstVarId)
553
+  {
554
+    case kFnMfId:
555
+      _cmDspMidiFilePlayOpen(ctx, inst );
556
+      break;
557
+
558
+    case kSelMfId:
559
+      {
560
+        if( cmDspSymbol(inst,kSelMfId)==p->startSymId ) 
561
+        {
562
+          p->csi       = cmDspInt(inst,kBsiMfId);
563
+          p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, p, p->csi );
564
+        }
565
+        break;
566
+      }
567
+
568
+  }
569
+  return kOkDspRC;
570
+}
571
+
572
+struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
573
+{
574
+  cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay",
575
+    NULL,
576
+    _cmDspMidiFilePlayAlloc,
577
+    _cmDspMidiFilePlayFree,
578
+    _cmDspMidiFilePlayReset,
579
+    _cmDspMidiFilePlayExec,
580
+    _cmDspMidiFilePlayRecv,
581
+    NULL,NULL,
582
+    "Time tagged text file.");
583
+
584
+  return &_cmMidiFilePlayDC;
585
+}
586
+
587
+//==========================================================================================================================================
588
+enum
589
+{
590
+  kFnSfId,
591
+  kWndCntSfId,
592
+  kWndMsSfId,
593
+  kIndexSfId,
594
+  kStatusSfId,
595
+  kD0SfId,
596
+  kD1SfId,
597
+  kOutSfId
598
+};
599
+
600
+cmDspClass_t _cmScFolDC;
601
+
602
+typedef struct
603
+{
604
+  cmDspInst_t inst;
605
+  cmScFol*    sfp;
606
+  cmScH_t     scH;
607
+} cmDspScFol_t;
608
+
609
+cmDspInst_t*  _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
610
+{
611
+  cmDspVarArg_t args[] =
612
+  {
613
+    { "fn",    kFnSfId,     0, 0, kInDsvFl | kStrzDsvFl   | kReqArgDsvFl,   "Score file." },
614
+    { "wndcnt",kWndCntSfId, 0, 0, kInDsvFl | kUIntDsvFl,                    "Event window element count." },
615
+    { "wndms", kWndMsSfId,  0, 0, kInDsvFl | kUIntDsvFl,                    "Event window length milliseconds."},
616
+    { "index", kIndexSfId,  0, 0, kInDsvFl | kUIntDsvFl,                    "Tracking start location."},
617
+    { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl,                    "MIDI status byte"},
618
+    { "d0",    kD0SfId,     0, 0, kInDsvFl | kUIntDsvFl,                    "MIDI data byte 0"},
619
+    { "d1",    kD1SfId,     0, 0, kInDsvFl | kUIntDsvFl,                    "MIDI data byte 1"},
620
+    { "out",   kOutSfId,    0, 0, kOutDsvFl| kUIntDsvFl,                    "Current score index."},
621
+    { NULL,    0,           0, 0, 0, NULL }
622
+  };
623
+
624
+  cmDspScFol_t* p;
625
+
626
+  if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
627
+    return NULL;
628
+  
629
+
630
+  p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle );
631
+
632
+  cmDspSetDefaultUInt( ctx, &p->inst,  kWndCntSfId,     0,    10);
633
+  cmDspSetDefaultUInt( ctx, &p->inst,  kWndMsSfId,      0,  5000);
634
+  cmDspSetDefaultUInt( ctx, &p->inst,  kIndexSfId,      0,     0);  
635
+  cmDspSetDefaultUInt( ctx, &p->inst,  kOutSfId,        0,     0);
636
+
637
+  return &p->inst;
638
+}
639
+
640
+cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
641
+{
642
+  cmDspScFol_t* p = (cmDspScFol_t*)inst;
643
+  cmScFolFree(&p->sfp);
644
+  cmScoreFinalize(&p->scH);
645
+  return kOkDspRC;
646
+}
647
+
648
+cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
649
+{
650
+  const cmChar_t* fn;
651
+  cmDspScFol_t* p  = (cmDspScFol_t*)inst;
652
+
653
+  if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 )
654
+    return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
655
+
656
+  if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, NULL ) != kOkScRC )
657
+    return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
658
+
659
+  return kOkDspRC;
660
+}
661
+
662
+cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
663
+{
664
+  cmDspRC_t     rc = kOkDspRC;
665
+  cmDspScFol_t* p  = (cmDspScFol_t*)inst;
666
+  rc               = cmDspApplyAllDefaults(ctx,inst);
667
+
668
+  if((rc = _cmDspScFolOpenScore(ctx,inst)) != kOkDspRC )
669
+    return rc;
670
+
671
+  if( cmScoreIsValid(p->scH) )
672
+    if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kWndCntSfId), cmDspUInt(inst,kWndMsSfId), p->scH) != cmOkRC )
673
+      rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
674
+
675
+  return rc;  
676
+}
677
+
678
+
679
+cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
680
+{ 
681
+  cmDspRC_t     rc = kOkDspRC;
682
+  cmDspScFol_t* p  = (cmDspScFol_t*)inst;
683
+
684
+  if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL )
685
+  {
686
+    switch( evt->dstVarId )
687
+    {
688
+      case kIndexSfId:
689
+        if( cmScFolReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC )
690
+          cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed.");
691
+        break;
692
+
693
+      case kStatusSfId:
694
+        {
695
+          unsigned idx = cmScFolExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId));
696
+          if( idx != cmInvalidIdx )
697
+            cmDspSetUInt(ctx,inst,kOutSfId,idx);
698
+        }
699
+        break;
700
+
701
+      case kFnSfId:
702
+        _cmDspScFolOpenScore(ctx,inst);
703
+        break;
704
+    }
705
+  }
706
+
707
+  return rc;
708
+}
709
+
710
+struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx )
711
+{
712
+  cmDspClassSetup(&_cmScFolDC,ctx,"ScFol",
713
+    NULL,
714
+    _cmDspScFolAlloc,
715
+    _cmDspScFolFree,
716
+    _cmDspScFolReset,
717
+    NULL,
718
+    _cmDspScFolRecv,
719
+    NULL,NULL,
720
+    "Score Follower");
721
+
722
+  return &_cmScFolDC;
723
+}
724
+

+ 1
- 0
dsp/cmDspKr.h View File

@@ -7,6 +7,7 @@ extern "C" {
7 7
 
8 8
   struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx );
9 9
   struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx );
10
+  struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx );
10 11
 
11 12
 #ifdef __cplusplus
12 13
 }

+ 40
- 3
dsp/cmDspPgmKr.c View File

@@ -36,16 +36,53 @@
36 36
 
37 37
 cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
38 38
 {
39
-  cmDspRC_t rc = kOkDspRC;
39
+  cmDspRC_t       rc      = kOkDspRC;
40
+  const cmChar_t* tlFn    = "/home/kevin/src/cmgv/src/gv/data/tl7.js";
41
+  const cmChar_t* audPath = "/home/kevin/media/audio/20110723-Kriesberg/Audio Files";
42
+  const cmChar_t* scFn    = "/home/kevin/src/cmgv/src/gv/data/mod2.csv";
43
+
44
+  cmDspInst_t* sci =  cmDspSysAllocInst(h,"Scalar", "ScIdx",  5, kNumberDuiId, 0.0,  10000.0, 1.0,  0.0);
45
+
46
+  cmDspInst_t* tlp  = cmDspSysAllocInst(h,"TimeLine",    "tl",  2, tlFn, audPath );
47
+  cmDspInst_t* php  = cmDspSysAllocInst(h,"Phasor",      NULL,  0 );
48
+  cmDspInst_t* wtp  = cmDspSysAllocInst(h,"WaveTable",   NULL,  2, cmDspSysSampleRate(h), 0 );
49
+  cmDspInst_t* pts  = cmDspSysAllocInst(h,"PortToSym",   NULL,  1, "start" );
50
+  cmDspInst_t* mfp  = cmDspSysAllocInst(h,"MidiFilePlay",NULL,  0 );
51
+  cmDspInst_t* sfp  = cmDspSysAllocInst(h,"ScFol",       NULL,  1, scFn );
52
+  cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut",    NULL,  1, 0 );
53
+  cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut",    NULL,  1, 1 );
54
+
55
+
40 56
 
41
-  cmDspInst_t* tlp = cmDspSysAllocInst(h,"TimeLine",   "text",      1, "Hello" );
42 57
   cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL,   1, ">" );
43 58
   
44 59
   if((rc = cmDspSysLastRC(h)) != kOkDspRC )
45 60
     return rc;
46 61
 
62
+  cmDspSysConnectAudio(h, php, "out", wtp,  "phs" );   // phs -> wt
63
+  cmDspSysConnectAudio(h, wtp, "out", ao0p, "in"  );   // wt  -> aout0
64
+  cmDspSysConnectAudio(h, wtp, "out", ao1p, "in" );    // wt  -> aout1
65
+
47 66
   
48
-  cmDspSysInstallCb(h, tlp, "val", prp, "in", NULL );
67
+  cmDspSysInstallCb(h, tlp, "afn",  prp, "in",  NULL );
68
+  cmDspSysInstallCb(h, tlp, "mfn",  prp, "in", NULL );
69
+  cmDspSysInstallCb(h, tlp, "sel",  prp, "in", NULL );
70
+
71
+  cmDspSysInstallCb(h, tlp, "absi", wtp, "beg", NULL );
72
+  cmDspSysInstallCb(h, tlp, "aesi", wtp, "end", NULL );
73
+  cmDspSysInstallCb(h, tlp, "afn",  wtp, "fn",  NULL );
74
+
75
+  cmDspSysInstallCb(h, tlp, "mbsi", mfp, "bsi", NULL );
76
+  cmDspSysInstallCb(h, tlp, "mesi", mfp, "esi", NULL );
77
+  cmDspSysInstallCb(h, tlp, "mfn",  mfp, "fn", NULL );
78
+  cmDspSysInstallCb(h, tlp, "mfn",  pts, "start", NULL );
79
+  cmDspSysInstallCb(h, pts, "out",  mfp, "sel", NULL );
80
+
81
+  cmDspSysInstallCb(h, mfp, "status", sfp, "status", NULL );
82
+  cmDspSysInstallCb(h, mfp, "d0",     sfp, "d0",     NULL );
83
+  cmDspSysInstallCb(h, mfp, "d1",     sfp, "d1",     NULL );
84
+  cmDspSysInstallCb(h, sci, "val",    sfp, "index",  NULL );
85
+  cmDspSysInstallCb(h, sfp, "out",    prp, "in",     NULL );
49 86
 
50 87
   return rc;
51 88
 }

+ 5
- 5
dsp/cmDspUi.c View File

@@ -361,10 +361,10 @@ cmDspRC_t  cmDspUiLabelCreate(  cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned lbl
361 361
   return rc;
362 362
 }
363 363
 
364
-cmDspRC_t  cmDspUiTimeLineCreate(   cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned valVarId, unsigned lblVarId, unsigned tlFileVarId, unsigned audPathVarId )
364
+cmDspRC_t  cmDspUiTimeLineCreate(   cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned tlFileVarId, unsigned audPathVarId, unsigned selVarId )
365 365
 {
366 366
   cmDspRC_t    rc;
367
-  unsigned     arr[] = { valVarId, lblVarId, tlFileVarId, audPathVarId  };
367
+  unsigned     arr[] = { tlFileVarId, audPathVarId, selVarId  };
368 368
   cmDspValue_t v;
369 369
   unsigned     vn    = sizeof(arr)/sizeof(arr[0]);
370 370
   cmDsvSetUIntMtx(&v,arr,vn,1);
@@ -374,14 +374,14 @@ cmDspRC_t  cmDspUiTimeLineCreate(   cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned
374 374
     return cmDspInstErr(ctx,inst,kUiEleCreateFailDspRC,"Time Line UI element create failed.");
375 375
 
376 376
   // use instance symbol as default label
377
-  if((rc = _cmDspUiUseInstSymbolAsLabel(ctx, inst, lblVarId, "TimeLine")) != kOkDspRC )
378
-    return rc;
377
+  //if((rc = _cmDspUiUseInstSymbolAsLabel(ctx, inst, lblVarId, "TimeLine")) != kOkDspRC )
378
+  //  return rc;
379 379
 
380 380
   // Set the kUiDsvFl on the variables used for the min/max/def/val for this scalar
381 381
   // Setting this flag will cause their values to be sent to the UI whenever they change.
382
-  cmDspInstVarSetFlags( ctx, inst, valVarId,     kUiDsvFl );
383 382
   cmDspInstVarSetFlags( ctx, inst, tlFileVarId,  kUiDsvFl );
384 383
   cmDspInstVarSetFlags( ctx, inst, audPathVarId, kUiDsvFl );
384
+  cmDspInstVarSetFlags( ctx, inst, selVarId,     kUiDsvFl );
385 385
   return rc;
386 386
 }
387 387
 

Loading…
Cancel
Save