download MKConductor.h
Language: ObjectiveC
Copyright: (c) 1988-1992, NeXT Computer, Inc. (c) 1994 Stanford University. (c) 1999-2005 The MusicKit Project. (c) 1994 NeXT Computer, Inc. and reproduced under license from NeXT
LOC: 189
Project Info
The MusicKit(musickit)
Server: SourceForge
Type: cvs
...sicKit\Frameworks\MusicKit\
   _ArielQP.h
   _DSPMK.h
   _error.h
   _midi.h
   _MKAppProxy.h
   _MKAppProxy.m
   _MKNameTable.h
   _MKNameTable.m
   _MKParameter.h
   _MTCHelper.h
   _MTCHelper.m
   _musickit.h
   _noteRecorder.h
   _OrchloopbeginUG.h
   _OrchloopbeginUG.m
   _ParName.h
   _ParName.m
   _scorefile.h
   _ScorefileVar.h
   _ScorefileVar.m
   _SharedSynthInfo.h
   _SharedSynthInfo.m
   _synthElementMethods.m
   _time.h
   ArielQP.h
   ArielQP.m
   classFuncs.h
   ConductorPrivate.h
   dsp_types.h
   DSPSerialPortDevice.h
   dspwrap.h
   EnvelopePrivate.h
   equalTempered.m
   errors.h
   fastFFT.c
   fastFFT.h
   GNUmakefile.postamble
   GNUmakefile.preamble.in
   InstrumentPrivate.h
   keynums.h
   libMusicKit.def
   Localized.strings
   make.sh
   Makefile.postamble
   Makefile.preamble
   midi_spec.h
   midifile.h
   midifile.m
   MidiPrivate.h
   midiTranslation.h
   MKConductor.h
   MKConductor.m
   MKConductorDelegate.h
   MKDeviceStatus.h
   MKEnvelope.h
   MKEnvelope.m
   MKFilePerformer.h
   MKFilePerformer.m
   MKFileWriter.h
   MKFileWriter.m
   MKInstrument.h
   MKInstrument.m
   MKMidi.h
   MKMidi.m
   MKMixerInstrument.h
   MKMixerInstrument.m
   MKMTCPerformer.h
   MKMTCPerformer.m
   MKNote.h
   MKNoteFilter.h
   MKNoteFilter.m
   MKNoteReceiver.h
   MKNoteReceiver.m
   MKNoteSender.h
   MKNoteSender.m
   MKOrchestra.h
   MKPart.m
   MKPartials.h
   MKPartials.m
   ...tialsWaveshapingTable.m
   MKPartPerformer.h
   MKPartPerformer.m
   MKPartRecorder.h
   MKPartRecorder.m
   MKPatch.h
   MKPatch.m
   MKPatchConnection.h
   MKPatchConnection.m
   MKPatchEntry.h
   MKPatchEntry.m
   MKPatchTemplate.h
   MKPatchTemplate.m
   MKPerformer.h
   MKPerformer.m
   MKPerformerDelegate.h
   MKPlugin.h
   MKSamplerInstrument.h
   MKSamplerInstrument.m
   MKSamples.h
   MKScore.h
   MKScore.m
   MKScorefileObject.h
   MKScorefilePerformer.h
   MKScorefilePerformer.m
   MKScorefileWriter.m
   MKScorePerformer.h
   MKScorePerformer.m
   MKScoreRecorder.h
   MKScoreRecorder.m
   MKSynthData.h
   MKSynthData.m
   MKSynthInstrument.h
   MKSynthPatch.h
   MKTimbre.h
   MKTimbre.m
   MKTuningSystem.h
   MKTuningSystem.m
   MKUnitGenerator.h
   MKUnitGenerator.m
   MKWaveTable.h
   MKWaveTable.m
   mtcMidi.m
   mtcMidiPrivate.m
   MusicKit-Info.plist
   MusicKit.h
   MusicKitConfig.h.in
   names.h
   noDVal.h
   noteDispatcherMethods.m
   NotePrivate.h
   noteRecorderCFuncs.m
   noteRecorderMethods.m
   orch.h
   OrchestraPrivate.h
   OrchloopbeginUG.h
   OrchloopbeginUG.m
   orchloopbeginUGInclude.m
   params.h
   parNames.m
   partialsDBInclude.m
   PartialsPrivate.h
   PartPerformerPrivate.h
   PartPrivate.h
   PartRecorderPrivate.h
   PatchTemplatePrivate.h
   PB.project
   PerformerPrivate.h
   pitches.h
   platform.make
   ...efilePerformerPrivate.h
   ScorePerformerPrivate.h
   ScorePrivate.h
   ScoreRecorderPrivate.h
   SynthDataPrivate.h
   synthElementCFuncs.m
   synthElementMethods.m
   SynthInstrumentPrivate.h
   SynthPatchList.h
   SynthPatchList.m
   SynthPatchPrivate.h
   timetagInclude.m
   timeunits.h
   tokenNames.m
   tokens.h
   trigonometry.c
   trigonometry.h
   TuningSystemPrivate.h
   UnitGeneratorPrivate.h
   win32-def.top
   writeBinary.m
   writeMidi.m
   writeScore.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
/*
  $Id: MKConductor.h,v 1.31 2005/05/27 09:52:25 leighsmith Exp $
  Defined In: The MusicKit

  Description:
    This is the header for the MusicKit scheduler. See documentation below for details.

  Original Author: David Jaffe

  Copyright (c) 1988-1992, NeXT Computer, Inc.
  Portions Copyright (c) 1994 NeXT Computer, Inc. and reproduced under license from NeXT
  Portions Copyright (c) 1994 Stanford University.
  Portions Copyright (c) 1999-2005 The MusicKit Project.
*/

#import <Foundation/Foundation.h>

@class MKMidi;
@class MKConductor;

/*!
  @class MKConductor
  @brief The MKConductor class defines the mechanism that controls the timing of a MusicKit performance. 
 
A MKConductor's most important tasks are
to schedule the sending of MKNotes by MKPerformers (and MKMidi), and
to control the timing of MKEnvelope objects during DSP synthesis.
Even in the absence of MKPerformers and MKEnvelopes, you may want to
use a MKConductor to take advantage of the convenient scheduling
mechanism that it provides.

Each instance of MKConductor contains a message request queue, a list
of messages that are to be sent to particular objects at specific
times.  To enqueue a message request with a MKConductor, you invoke
the <b>sel:to:atTime:argCount:</b> or
<b>sel:to:withDelay:argCount:</b> method.  The former sends a message
at a specific time measured in beats from the time the MKConductor
started performing, while the latter sends the message a specified
number of beats after the request is received.  Once you have made a
message request through these methods, you can't rescind the action;
if you need more control over message requests - for example, if you
need to be able to reschedule or remove a request - you should use the
following C functions:

<ul>
<li> <b>MKNewMsgRequest()</b> creates and returns a new message
request structure.

<li> <b>MKScheduleMsgRequest()</b> places a previously created
message request (structure) in a specific MKConductor's message
request queue.

<li> <b>MKRepositionMsgRequest()</b> repositions a message request
within a MKConductor's queue.

<li> <b>MKCancelMsgRequest()</b> removes a message request.

<li> <b>MKRescheduleMsgRequest()</b> is a convenience function that
cancels a request and then creates a new one.
</ul>

For more information on these functions, see Chapter 3, "C Functions."

The MKConductor class provides two special message request queues, one
that contains messages that are sent at the beginning of a performance
and another for messages that are sent after a performance ends.  The
class methods <b>beforePerformanceSel:to:argCount:</b> and
<b>afterPerformanceSel:to:argCount: </b>enqueue message requests in
the before- and after-performance queues, respectively.

A MusicKit performance starts when the MKConductor class receives the
<b>startPerformance</b> message.  At that time, the MKConductor class
sends the messages in its before-performance queue and then the
MKConductor instances start processing their individual message
request queues.  As a message is sent, the request that prompted the
message is removed from its queue.  The performance ends when the
MKConductor class receives <b>finishPerformance</b>, at which time the
after-performance messages are sent. Any message requests that remain
in the individual MKConductors' message request queues are removed.
Note, however, that the before-performance queue isn't similarly
cleared.  If you invoke <b>beforePerformanceSel:to:argCount:
</b>during a performance, the message request will survive a
subsequent <b>finishPerformance</b> and will affect the next
performance.

By default, if all the MKConductors' queues become empty at the same
time (not including the before- and after-performance queues),
<b>finishPerformance</b> is invoked automatically.  This is convenient
if you're performing a MKPart or MKScore and you want the performance
to end when all the MKNotes have been played.  However, for many
applications, such as those that create and perform MKNotes in
response to a user's actions, universally empty queues isn't
necessarily an indication that the performance is over.  To allow a
performance to continue even if all the queues are empty, send
<b>setFinishWhenEmpty:NO</b> to the MKConductor class.

You can pause and resume an entire performance through methods sent to
the MKConductor class:

<ul>
<li> <b>pausePerformance</b> causes all MKConductor instances to
stop processing their message request queues.

<li> <b>resumePerformance</b> resumes a paused performance.  
</ul>

These messages are ignored if a performance isn't in progress.

You can pause and resume individual MKConductor objects through the
<b>pause</b> and <b>resume</b> methods.  In addition, you can pause a
MKConductor object for a predetermined number of seconds (not beats)
through <b>pauseFor:</b>.  To offset the begin time of a
MKConductor<b></b> object before a performance starts, invoke
<b>setTimeOffset:</b>.  Here again, the arguments is taken as seconds.
You can also offset the begin time of a MKConductor object by an
indeterminate amount of time by sending it the <b>pause</b> message
before a performance begins and then sending it <b>resume</b> while
the performance is in progress.  After a performance has ended, all
currently paused MKConductor objects are (virtually) resumed.  Thus, a
MKConductor object is guaranteed not to be paused when a performance
starts (unless, of course, you have specifically sent it the
<b>pause</b> message since <b>finishPerformance</b> was last sent).

A MKConductor object can be given a delegate that's sent the
<b>hasPaused:</b> message when the MKConductor is paused and
<b>hasResumed:</b> when the MKConductor resumes.  As in the AppKit's
delegate paradigm, a delegate messages is sent only if the delegate
responds to it.

The rate at which a MKConductor object processes its message request
queue can be set through either the <i>Tempo Protocol</i> or the
<i>Time Map Protocol</i>. The <i>Tempo Protocol</i> consists of the
following two methods (you may use either):

<ul>
<li> <b>setTempo:</b> sets the rate as beats per minute.
<li> <b>setBeatSize:</b> sets the size of an individual beat, in seconds. 
</ul>
 
You can change a MKConductor's tempo anytime, even during a
performance.  If your application requires multiple simultaneous
tempi, you need to create more than one MKConductor, one for each
tempo.  A MKConductor's tempo is initialized to 60.0 beats per minute.

An alternative way to modify tempo is to use a tempo track or "Time
Map".  This protocol relies on the MKConductor's delegate to implement
two methods that specify the mapping between "beat time" and "clock
time."  If the delegate implements one of these methods, it must
implement both.  By implementing these methods, the delegate specifies
that it is using the <i>Time Map Protocol</i>.  The two methods are
<b>beatToClock:from:</b> and <b>clockToBeat:from:</b>.  These methods
map from pre-tempo to post-tempo time.  For details, see 
<a href=http://www.musickit.org/MusicKitConcepts/musicperformance.html>
the section entitled Music Performance
</a>

The responsiveness of a performance to the user's actions depends on
whether the MKConductor class is clocked and upon the value of the
performance's <i>delta time</i>.  By default, the MKConductor class is
clocked which means that message request queues are processed in a
timely fashion: If, for example, two requests are specified to be sent
one beat apart, then the message sending mechanism sends the first
message and then, one beat later, sends the second message.  When the
MKConductor class is clocked, a running NSApplication object is
assumed to be present.  If you don't need interactive control over a
performance, you may find it beneficial to have the messages in the
message request queues sent one after another as quickly as possible,
while depending on another device, such as the DSP or MIDI drivers, to
handle the timing of the actual realization (this is further explained
in the descriptions of the MKOrchestra and MKMidi classes).  To allow
the queues to be processed in this way, you set the MKConductor class
to be unclocked by sending it the <b>setClocked:NO</b> message.  If
you set the MKConductor class to be unclocked, be aware that the
<b>startPerformance</b> method doesn't return until the performance is
over.  (In this situation, sending <b>setFinishWhenEmpty:NO</b> to the
MKConductor class is ill-advised since <b>startPerformance</b> would
never return.)

Setting a performance's delta time further refines the responsiveness
of a performance. Delta time is set through the <b>setDeltaT:</b>
class method; the argument defines an imposed time lag, in seconds,
between the MKConductor's notion of time and that of the DSP and MIDI
device drivers.  It acts as a timing cushion that can help to maintain
rhythmic integrity by granting your application a sort of
computational head start: As you set the delta time to larger values,
your application has more time to process MKNotes before they are
realized.  However, this computational advantage is obtained at the
expense of degraded responsiveness.  Choosing the proper delta time
value depends on how responsive your application needs to be.  For
example, if you are driving DSP synthesis from MIDI input (in other
words, you have a MKMidi object connected to a MKSynthInstrument -
this is usually the most demanding scenario in terms of desired
real-time response), a delta time of as much as 10 milliseconds (0.01
seconds) is generally acceptable.  If you are adjusting MKNote
parameters by moving a NSSlider with the mouse, a delta time of 100
milliseconds or more can be tolerated.  Finding the right delta time
for your application is largely a matter of experimentation.

Every MKConductor instance has a notion of the current time measured
in its own tempo, as returned by sending it the <b>time</b> message.
The returned value is the number of beats the receiver has spent in
performance and doesn't include the receiver's time offset, any time
it has spent while paused, nor does it include the performance's delta
time.  The MKConductor class also responds to the <b>time</b> message;
it returns the current duration of the performance in seconds,
excluding any time that the entire performance has been paused (and
also excluding deltat time).  The value returned by the <b>time</b>
message, whether sent to the MKConductor class or to an instance, is
actually the time at which the last message from any of the
MKConductors' queues was sent.  This latency is present because the
MKConductor class updates its notion of time (from which all the
MKConductor instances compute their time) only when a message from one
of the request queues is sent.  If your application sends a message
(or calls a C function) in response to an asynchronous event, it must
first update the MKConductors' notions of time by bracketing the code
you invoke with <b>[MKConductor lockPerformance]</b> and
<b>[MKConductor unlockPerformance]</b>.  You should send these
messages before performing tasks such as pausing or resuming a
MKConductor - you should even send them immediately before sending
<b>finishPerformance</b>.  If, for yet another example, your
application sends MKNotes directly to MKInstruments, you should send
<b>lockPerformance</b> immediately before each MKNote is sent and
<b>unlockPerformance</b> afterwards.  (This API supercedes the older
<b>adjustTime</b>, which will still work only if the MusicKit is not
run in a separate thread.  See <b>+useSeparateThread:</b>.)

MKConductors and MKPerformers have a special relationship: Every
MKPerformer object is controlled by an instance of MKConductor, as set
through MKPerformer's <b>setConductor:</b> method.  While a
MKPerformer can be controlled by only one MKConductor, a single
MKConductor can control any number of MKPerformers.  As a MKPerformer
acquires successive MKNotes, it enqueues, with its associated
MKConductor, requests for the MKNotes to be sent to its connected
MKInstruments. This enqueuing is performed automatically through a
mechanism defined by the MKPerformer class. As a convenience, the
MusicKit automatically creates an instance of MKConductor called the
<i>defaultConductor</i>; if you don't set a MKPerformer's MKConductor
directly, it's controlled by the defaultConductor. You can retrieve the
defaultConductor (in order to set its tempo or to enqueue message
requests, for example) by sending the <b>defaultConductor</b> message
to the MKConductor class.

The MusicKit also creates an instance of MKConductor called the
<i>clockConductor</i>, which you can retrieve through the
<b>clockConductor</b> class method.  The clockConductor has an
unchangeable tempo of 60.0 beats per minute and can't be paused.
While the clockConductor can be used to control MKPerformers, its
most important task is to control the timing of MKEnvelope objects
during DSP synthesis.  All MKEnvelopes are controlled by the
clockConductor automatically.  The clockConductor also controls
the duration of any MKNoteDurs that you send directly to an
MKInstrument. In other words, the duration of such a MKNote is always
computed using the 60.0 beats-per-minute tempo of the clockConductor.  

The clockConductor's queue is treated like any other queue:
You can enqueue message requests with the clockConductor just as
you would with any other MKConductor. This also means that the
clockConductor's queue contributes to a determination of whether
all the queues are empty.

MKConductors can synchronize to incoming MIDI time code. This functionality is described in 
<a href=http://www.musickit.org/MusicKitConcepts/miditimecode.html>
Appendix B. entitled MIDI Time Code in the MusicKit</a>.

  @see MKPerformer, MKOrchestra, MKMidi
*/
#ifndef __MK_Conductor_H___
#define __MK_Conductor_H___

#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSThread.h>
#import <SndKit/SndKit.h>

// Enforce C name mangling to allow linking MusicKit functions to C++ code
#ifdef __cplusplus
extern "C" {
#endif

 /* The MKConductor message structure.  All fields are private and
  * shouldn't be altered directly from an application.
  * LMS: should become an object named MKConductorMsg
  */
/*!
  @brief <b>MKMsgStruct</b> is the structure that represents a message the MKConductor will send to an object.
  @see <b>MKNewMsgRequest</b>(), <b>MKScheduleMsgRequest</b>(), <b>MKCancelMsgRequest</b>(), <b>MKRescheduleMsgRequest</b>(), and <b>MKRepositionMsgRequest</b>().
 */
typedef struct _MKMsgStruct { 
    double _timeOfMsg;     
    SEL _aSelector;       
    id _toObject;	       
    int _argCount;             
    BOOL _retainArg1;
    BOOL _retainArg2;
    id _arg1;
    id _arg2;
    struct _MKMsgStruct *_next;	
    IMP _methodImp;        
    id *_otherArgs;
    BOOL _conductorFrees;  
    BOOL _onQueue;      
    struct _MKMsgStruct *_prev;
    MKConductor *_conductor;
} MKMsgStruct;

/*! Largest time value that may be scheduled with the MKConductor. */
#define MK_ENDOFTIME (6000000000.0) /* A long time, but not as long as MK_FOREVER */

/*!
  @defgroup TimeFns Set and get MusicKit time values.
 */
/*!
  @brief Returns the time in seconds. 

  <b>MKGetTime()</b> returns the current time, in seconds, during a MusicKit
  performance. In a conducted performance (the norm), this is the
  same as [MKConductor time]. 
   
  @return Returns a double.
  @ingroup TimeFns
*/
extern double MKGetTime(void);

/*!
  @brief Returns deltaT, in seconds.

   <b>MKGetDeltaT()</b> returns the delta time value, in seconds. The
  meaning of delta time depends on whether the performance is clocked or
  unclocked.  In a clocked performance, the MKConductor tries to stay
  <i>approximately</i> delta time seconds ahead of the devices (e.g. DSP).
  In an unclocked performance, MKConductor tries to stay <i>at least</i>
  delta time seconds ahead of the devices. Delta time has an effect only
  if the device is in timed mode.
   
  @return Returns a double.
  @ingroup TimeFns
*/
extern double MKGetDeltaT(void);

/*!
  @brief Sets deltaT, in seconds.

  <b>MKSetDeltaT()</b> sets a performance's delta time in seconds.  The
  delta time value is used in one of two ways, depending on the delta time
  "mode", which is set with <b>MKSetDeltaTMode()</b>.  In
  MK_DELTAT_DEVICE_LAG mode, deltaT is added into the timestamps of DSP
  and MIDI messages, thus imposing a time lag between the MusicKit and
  these devices. If, on the other hand, the delta time mode is
  MK_DELTAT_SCHEDULER_ADVANCE, then deltaT is the amount by which the
  MusicKit MKConductor attempts to run ahead of the devices.  In either
  case, the lag is sometimes necessary to allow the MusicKit sufficient
  compute time while maintaining rhythmic integrity.  Effective delta time
  values can be quite small; for an application that requires real-time
  response, a delta time of as much as 10 milliseconds (0.01 seconds) is
  tolerable.  Delta time only affects devices that are timed.  In
  addition, in order for the delta time value to be valid, the performance
  and the devices must be started at (virtually) the same time.  That is,
  send <b>[orchestra run]</b> and <b>[midi run]</b> immediately before
  sending <b>[MKConductor startPerformance]</b>;
   
  @param  val is a double.
  @return Returns a double.
  @ingroup TimeFns
*/
extern void MKSetDeltaT(double val);

/*!
  @brief Returns deltaT + time, in seconds.
   
  <b>MKGetDeltaTTime()</b> returns the sum of the values returned by
  <b>MKGetTime()</b> and <b>MKGetDeltaT()</b>.
  @return Returns a double.
  @ingroup TimeFns
*/
extern double MKGetDeltaTTime(void);

/*!
  @brief These constants control the <i>deltaT mode</i>, determining how deltaT is interpreted.. 
  @see MKConductor and the Performance Concepts documentation for details.
 */
/*! Commands to device have an offset added to their time. */
#define MK_DELTAT_DEVICE_LAG 0
/*! Scheduler (MKConductor) subtracts offset from the time it uses internally to schedule messages. */
#define MK_DELTAT_SCHEDULER_ADVANCE 1
 
/*!
  @brief Sets the delta time mode.
 
  Sets the delta time mode to one of MK_DELTAT_DEVICE_LAG or MK_DELTAT_SCHEDULER_ADVANCE.
  The default is MK_DELTAT_DEVICE_LAG.
  @param  newMode is an int.
  @ingroup TimeFns
*/
extern void MKSetDeltaTMode(int newMode);

/*!
  @brief Returns the delta time mode. 
  @return Returns an extern.
  @ingroup TimeFns
*/
extern int MKGetDeltaTMode(void);

/*!
  @brief Set the performance time.

  Rarely used. <b>MKSetTime()</b> and <b>MKFinishPerformance()</b> are provided to
  set the performance time and to end a performance, respectively, <i>but
  only in the case of a performance that doesn't use the MKConductor
  class</i>.  During a conducted performance, <b>MKSetTime()</b>
  has no effect and <b>MKFinishPerformance()</b> is the same as sending
  <b>finishPerformance</b> to the MKConductor class.    Precisely,
  <b>MKFinishPerformance()</b> his the effect of evaluating the
  MKConductor's "after performance" queue of messages, which in turn tells
  the MKPerformers and MKInstruments that the performance is finished. 
  @param  newTime is a double.
  @return Returns a double.
  @ingroup TimeFns
*/
extern double MKSetTime(double newTime);

/*!
  @defgroup Create and manipulate MKConductor message requests.
 */
/*@{*/
/*!
  @brief Creates and returns a new MKMsgStruct.

  These functions let you enqueue message requests with a MKConductor
  object.  The  MKMsgStruct structure encapulates a message request; it
  consists of a method selector and its arguments, the recipient of the
  message, and the time that the message should be sent.  A selector can
  take a maximum of two 4-byte arguments.  You should never modify the
  fields of a MKMsgStruct structure directly.  
   
  <i>timeOfMsg</i> is the time in beats from the beginning of the
  performance that the message will be sent, <i>whichSelector</i> is the
  selector, <i>destinationObject</i> is the recipient of the message, and
  <i>argCount</i> is the number of arguments to the selector followed by
  the arguments themselves separated by commas.   
   
   After you've created a message request structure, you schedule it
  with a MKConductor by calling <b>MKScheduleMsgRequest()</b>.
     
   If you want to move a message request within a MKConductor's queue
  you call the <b>MKRepositionMsgRequest()</b> function.  The specified
  MKMsgStruct is moved to the time given by <i>newTimeOfMsg.</i>  You
  should note that the MKMsgStruct that you pass as the
  <i>aMsgStructPtr</i> argument may be replaced with a new structure
  that's returned by the function<i>.</i>  To make sure you don't keep
  around a pointer to an obsolete struct, call this function as follows:  
     
   <tt>	// Reposition and prime aMsgReq for additional functions calls.</tt>
   <tt>	aMsgReq = MKRepositionMsgRequest(aMsgReq, 3.0);</tt>
     
   <b>MKCancelMsgRequest()</b> cancels the given message request and
  frees the structure pointed to by <i>aMsgStructPtr.   </i>Be sure not to
  cancel an already-canceled request.  To make sure you don't do that, you
  should assign the returned value of the function (NULL) to the value you
  pass.  Example of use:
   
   <tt>	aMsgReq = MKCancelMsgRequest(aMsgReq);</tt>
   <tt>	// aMsgReq is now NULL</tt>
   
   <b>MKRescheduleMsgRequest()</b> is a convenience function that
  cancels the structure pointed to by <i>aMsgStructPtr</i>, and then
  creates and schedules a new request according to the arguments.  The new
  MKMsgStruct is returned.
  @param  timeOfMsg is a double.
  @param  whichSelector is a SEL.
  @param  destinationObject is an id.
  @param  argCount is an int.
  @return Return <i>NULL if argCount</i> is greater than 2.
*/
extern MKMsgStruct 
  *MKNewMsgRequest(double timeOfMsg, SEL whichSelector, id destinationObject, int argCount, ...);

extern MKMsgStruct 
  *MKNewMsgRequestWithObjectArgs(double timeOfMsg, SEL whichSelector, id destinationObject,
		   int argCount, id arg1, BOOL, id arg2, BOOL);

/*!
  @brief Create and manipulate MKConductor message requests

  These functions let you enqueue message requests with a MKConductor
  object.  The  MKMsgStruct structure encapulates a message request; it
  consists of a method selector and its arguments, the recipient of the
  message, and the time that the message should be sent.  A selector can
  take a maximum of two 4-byte arguments.  You should never modify the
  fields of a MKMsgStruct structure directly.  
   
  <b>MKNewMsgRequest()</b> creates and returns a new MKMsgStruct. 
  <i>timeOfMsg</i> is the time in beats from the beginning of the
  performance that the message will be sent, <i>whichSelector</i> is the
  selector, <i>destinationObject</i> is the recipient of the message, and
  <i>argCount</i> is the number of arguments to the selector followed by
  the arguments themselves separated by commas.   
   
   After you've created a message request structure, you schedule it
  with a MKConductor by calling <b>MKScheduleMsgRequest()</b><i>.</i>
     
  @param  aMsgStructPtr is a MKMsgStruct.
  @param  conductor is an id.
*/
extern void MKScheduleMsgRequest(MKMsgStruct *aMsgStructPtr, id conductor);

/*!
  @brief Create and manipulate MKConductor message requests

  These functions let you enqueue message requests with a MKConductor
  object.  The  MKMsgStruct structure encapulates a message request; it
  consists of a method selector and its arguments, the recipient of the
  message, and the time that the message should be sent.  A selector can
  take a maximum of two 4-byte arguments.  You should never modify the
  fields of a MKMsgStruct structure directly.  
   
  <b>MKCancelMsgRequest()</b> cancels the given message request and
  frees the structure pointed to by <i>aMsgStructPtr.   </i>Be sure not to
  cancel an already-canceled request.  To make sure you don't do that, you
  should assign the returned value of the function (NULL) to the value you
  pass.  Example of use:
   
   <tt>	aMsgReq = MKCancelMsgRequest(aMsgReq);</tt>
   <tt>	// aMsgReq is now NULL</tt>
   
  @param  aMsgStructPtr is a MKMsgStruct *.
  @return Returns a MKMsgStruct *.
*/
extern MKMsgStruct *MKCancelMsgRequest(MKMsgStruct *aMsgStructPtr);

/*!
  @brief Create and manipulate MKConductor message requests

  These functions let you enqueue message requests with a MKConductor
  object.  The  MKMsgStruct structure encapulates a message request; it
  consists of a method selector and its arguments, the recipient of the
  message, and the time that the message should be sent.  A selector can
  take a maximum of two 4-byte arguments.  You should never modify the
  fields of a MKMsgStruct structure directly.  
   
  <b>MKRescheduleMsgRequest()</b> is a convenience function that
  cancels the structure pointed to by <i>aMsgStructPtr</i>, and then
  creates and schedules a new request according to the arguments.  The new
  MKMsgStruct is returned.
  @param  aMsgStructPtr is a MKMsgStruct.
  @param  conductor is an id.
  @param  timeOfNewMsg is an id.
  @param  whichSelector is a double.
  @param  destinationObject is a SEL.
  @param  argCount is an int.
  @return Returns a MKMsgStruct *.
*/
extern MKMsgStruct *
  MKRescheduleMsgRequest(MKMsgStruct *aMsgStructPtr, id conductor,
			 double timeOfNewMsg, SEL whichSelector,
			 id destinationObject, int argCount, ...);

extern MKMsgStruct *
  MKRescheduleMsgRequestWithObjectArgs(MKMsgStruct *aMsgStructPtr, id conductor,
			 double timeOfNewMsg, SEL whichSelector,
			 id destinationObject, int argCount,
			 id arg1, BOOL retainArg1,
			 id arg2, BOOL retainArg2);

/*!
  @brief Create and manipulate MKConductor message requests

  These functions let you enqueue message requests with a MKConductor
  object.  The  MKMsgStruct structure encapulates a message request; it
  consists of a method selector and its arguments, the recipient of the
  message, and the time that the message should be sent.  A selector can
  take a maximum of two 4-byte arguments.  You should never modify the
  fields of a MKMsgStruct structure directly.  
   
  If you want to move a message request within a MKConductor's queue
  you call the <b>MKRepositionMsgRequest()</b> function.  The specified
  MKMsgStruct is moved to the time given by <i>newTimeOfMsg.</i>  You
  should note that the MKMsgStruct that you pass as the
  <i>aMsgStructPtr</i> argument may be replaced with a new structure
  that's returned by the function<i>.</i>  To make sure you don't keep
  around a pointer to an obsolete struct, call this function as follows:  
     
<pre>
	// Reposition and prime aMsgReq for additional functions calls.
   	aMsgReq = MKRepositionMsgRequest(aMsgReq, 3.0);
</pre>
     
  @param  aMsgStructPtr is a MKMsgStruct *.
  @param  newTimeOfMsg is a double.
  @return Returns a MKMsgStruct *.
*/
extern MKMsgStruct *MKRepositionMsgRequest(MKMsgStruct *aMsgStructPtr, double newTimeOfMsg);
/*@}*/

/*!
  @brief Set and get MusicKit time values

  <b>MKGetTime()</b> returns the current time, in seconds, during a Music
  Kit performance.   In a conducted performance (the norm), this is the
  same as [MKConductor time]. 
   
   <b>MKSetDeltaT()</b> sets a performance's delta time in seconds.  The
  delta time value is used in one of two ways, depending on the delta time
  "mode", which is set with <b>MKSetDeltaTMode()</b>.  In
  MK_DELTAT_DEVICE_LAG mode, deltaT is added into the timestamps of DSP
  and MIDI messages, thus imposing a time lag between the MusicKit and
  these devices. If, on the other hand, the delta time mode is
  MK_DELTAT_SCHEDULER_ADVANCE, then deltaT is the amount by which the
  MusicKit MKConductor attempts to run ahead of the devices.  In either
  case, the lag is sometimes necessary to allow the MusicKit sufficient
  compute time while maintaining rhythmic integrity.  Effective delta time
  values can be quite small; for an application that requires real-time
  response, a delta time of as much as 10 milliseconds (0.01 seconds) is
  tolerable.  Delta time only affects devices that are timed.  In
  addition, in order for the delta time value to be valid, the performance
  and the devices must be started at (virtually) the same time.  That is,
  send <b>[orchestra run]</b> and <b>[midi run]</b> immediately before
  sending <b>[MKConductor startPerformance]</b>;
   
   <b>MKGetDeltaT()</b> returns the delta time value, in seconds. The
  meaning of delta time depends on whether the performance is clocked or
  unclocked.  In a clocked performance, the MKConductor tries to stay
  <i>approximately</i> delta time seconds ahead of the devices (e.g. DSP).
  In an unclocked performance, MKConductor tries to stay <i>at least</i>
  delta time seconds ahead of the devices. Delta time has an effect only
  if the device is in timed mode.
   
   <b>MKGetDeltaTTime()</b> returns the sum of the values returned by
  <b>MKGetTime()</b> and <b>MKGetDeltaT()</b>.  
   
   <b>MKSetTime()</b> and <b>MKFinishPerformance()</b> are provided to
  set the performance time and to end a performance, respectively, <i>but
  only in the case of a performance that doesn't use the MKConductor
  class.</i>  <i></i> During a conducted performance, <b>MKSetTime()</b>
  has no effect and <b>MKFinishPerformance()</b> is the same as sending
  <b>finishPerformance</b> to the MKConductor class.    Precisely,
  <b>MKFinishPerformance()</b> his the effect of evaluating the
  MKConductor's "after performance" queue of messages, which in turn tells
  the Performers and Instruments that the performance is finished. 
     
   <b>MKSetLowDeltaTThreshold()</b> and <b>MKSetHighDeltaTThreshold()</b> controls the high and low watermark for the delta time notification mechanism. For example, to receive a message when the MKConductor has fallen behind such that the effective delta time is less than 1/4 of the value of MKGetDeltaT(), you'd call <b>MKSetLowDeltaTThreshold(.25);</b>  Similarly, to receive a message when the MKConductor has recovered such that the effective delta time is more than 3/4 of the value of <b>MKGetDeltaT()</b>, you'd call <b>MKSetHighDeltaTThreshold(.75);  </b>This mechanism allows you to receive a warning when the MKConductor is about to fall out of real time, due to heavy computation.   For example, you might want to automatically reduce the tempo in this case.  The notification itself is sent to the MKConductor class' delegate object.  See MKConductor.h for further details.  
   
   <b>MKSetDeltaTMode();</b>  Sets the delta time mode to one of
  MK_DELTAT_DEVICE_LAG or MK_DELTAT_SCHEDULER_ADVANCE .    The default is
  MK_DELTAT_DEVICE_LAG.
   
   <b>MKGetDeltaTMode();</b>  Returns the delta time mode.
*/
extern void MKFinishPerformance(void);

@interface MKConductor: NSObject
{
  /*! @var time Current Time in beats, updated (for all instances) after timed entry fires off. */
    double time;       
  /*! @var nextMsgTime Time, in seconds, when next message is scheduled to be sent by this MKConductor. */
    double nextMsgTime;           // sb: relative to start of performance, I think.
    /* nextMsgTime = (nextbeat - time) * beatSize */
  /*! @var beatSize The duration of a single beat in seconds. */
    double beatSize;    
  /*! @var timeOffset Performance timeOffset in seconds. */
    double timeOffset;
  /*! @var isPaused YES if this instance is paused. Note that pausing
    all MKConductors through the pause factory method doesn't set this
    to YES. */ 
    BOOL isPaused;      
  /*! @var delegate The object's delegate. */
    id delegate;
  /*! @var activePerformers NSMutableArray object of active performers
    using this conductor. Don't alter this NSMutableArray. */
    NSMutableArray *activePerformers;
  /*! @var MTCSync MIDI Time Code synchronization object, if any. */
    id MTCSynch;

    /* Internal use only */
@private
    MKMsgStruct *_msgQueue;
    MKConductor *_condNext;
    MKConductor *_condLast;
    double _pauseOffset;
    double inverseBeatSize;
    double oldAdjustedClockTime;
    MKMsgStruct *pauseFor;
    unsigned char archivingFlags;
    unsigned char delegateFlags;
}
 
+ allocWithZone: (NSZone *) zone;

/*!
  @return Returns an id.
  @brief Creates and returns a new MKConductor object with a tempo of 60.0
  beats per minute, allocated from the default zone.

  You must send
  <b>init </b>to the new instance.  If a performance is currently in
  progress, this does nothing and returns <b>nil</b>.
*/
+ alloc;

/*!
  @return Returns an id.
  @brief Initializes a new MKConductor.

  You must send this message after
  using <b>alloc</b> or <b>allocFromZone:</b> to create a
  MKConductor.
*/
- init;

/*!
  @return Returns an id.
  @brief <i>This method is superceded by <b>+lockPerformance </b>and
  <b>+unlockPerformance</b>.</i>  
  
  Updates every MKConductor's notion of time.

  This method
  may be invoked just before you send a message or call a
  C function that affects the performance.  Typical
  examples include methods that are in response to the
  user's actions, methods that send MKNotes directly to
  MKInstruments, and methods, such as <b>pause</b> and
  <b>resume</b>, that are sent to a MKConductor object or
  to the MKConductor class.  You do not need to send this
  message if you are invoked in response to MKConductor or
  MKMidi messages.  Returns the receiver.
*/
+ adjustTime; 

/*!
  @brief Starts a performance.
  @return Returns an id.
  
  All MKConductor objects begin at the same
  time.  If the performance is clocked and you don't have a running
  NSRunLoop, this does nothing and returns <b>nil</b>.
			  In all other cases, the receiver is returned; however,
  if the performance is unclocked, this method doesn't return until
  the performance is over.
*/
+ startPerformance;

/*!
  @return Returns an MKConductor.
  @brief Returns the defaultConductor.

  
*/
+ (MKConductor *) defaultConductor; 

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if a performance is currently taking place (even
  if it's paused), otherwise returns <b>NO</b>.

  
*/
+(BOOL) inPerformance; 

/*!
  @return Returns an id.
  @brief Ends the performance.

  All enqueued messages are removed (from
  MKConductor instances' message queues - not from the before- and
  after-performance queues) and the <b>after-performance</b> messages
  are sent<b>. </b>If<b> finishWhenEmpty</b> is <b>YES</b>, this
  message is automatically sent when all message queues are exhausted.
  Returns <b>nil</b>.
*/
+ finishPerformance; 

/*!
  @return Returns an id.
  @brief Pauses the performance.

  The performance is suspended until the
  MKConductor class receives the <b>resumePerformance</b> message. 
  You can't pause an unclocked performance; returns <b>nil</b> if the
  performance is unclocked.  Otherwise returns the receiver.  This
  message is ignore and the receiver is returned if a performance
  isn't in progress.  You cannot pause a performance in which a
  MKConductor is synchronizing to MIDI time code.   An attempt to do
  so will be ignored.     
*/
+ pausePerformance; 

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if the performance is paused, otherwise returns
  <b>NO</b>.

  
*/
+ (BOOL) isPaused; 

/*!
  @return Returns an id.
  @brief Resumes a  performance, allowing it to continue from where it was
  paused.

  If the performance is unclocked, return <b>nil</b>,
  otherwise returns the receiver.
*/
+ resumePerformance; 

/*!
  @return Returns an id.
  @brief Returns the MKConductor instance that's currently sending a message,
  or <b>nil</b> if no message is being sent.

  
*/
+ currentConductor; 

/*!
  @return Returns an id.
  @brief Returns the clockConductor.

  
*/
+ clockConductor;

/*!
  @param  yesOrNo is a BOOL.
  @return Returns an id.
  @brief If <i>yesOrNo</i> is <b>YES</b> (the default), the MKConductors
  dispatches each message at the specified time, waiting if necessary.

  
  If <b>NO</b>, messages are sent as quickly as possible.  In an
  unclocked performance, a subsequent startPerformance message doesn't
  return until the performance is over, thus effectively disabling the
  user interface.  Does nothing and returns <b><i>nil</i></b><i></i>
  if a performance is in progress, otherwise returns the
  receiver.<i></i>   Unclocked performances involving MIDI time code
  conductors are not supported.   
*/
+ setClocked: (BOOL) yesOrNo; 

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if the performance is clocked, <b>NO</b> if it
  isn't.

  By default, a performance is clocked.
*/
+ (BOOL) isClocked; 

/*!
  @param  yesOrNo is a BOOL.
  @return Returns an id.
  @brief If <i>yesOrNo</i> is <b>YES</b> (the default), the performance is
  terminated when all the MKConductors' message queues are empty.

  If
  <b>NO</b>, the performance continues until the
	  <b>finishPerformance</b> message is sent to the MKConductor class.
*/
+ setFinishWhenEmpty: (BOOL) yesOrNo; 

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if a performance is in progress and all the
  MKConductor instances' message request queues are are empty,
  otherwise returns <b>NO.</b>
*/
+ (BOOL) isEmpty;

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if the performance will finish when all
  MKConductors' message queues are empty, <b>otherwise returns
  NO</b>.

  
*/
+ (BOOL) finishWhenEmpty;

/*!
  @param  newDeltaT is a double.
  @brief Set the delta time in seconds.

  
  @see <b>MKSetDeltaT()</b>
*/
+ (void) setDeltaT: (double) newDeltaT;

/*!
  @return Returns a double.
  @brief Returns the delta time in seconds.

  
*/
+ (double) deltaT;

/*!
  @return Returns an id.
  @brief Returns a new MKConductor created through <b>[MKConductor new]</b>.

  
*/
- copyWithZone: (NSZone *) zone;

/*!
  @return Returns a BOOL.
  @brief Returns <b>YES</b> if the receiver is paused.

  
*/
- (BOOL) isPaused; 

/*!
  @return Returns an id.
  @brief Pauses the performance of the receiver and sends <b>hasPaused:</b>
  to its delegate.

  The effect is restricted to the present
  performance.  Invoke <b>resume</b> to unpause a MKConductor.  You
  can't pause the clockConductor; returns <b>nil</b> in this case (and
  the delegate message isn't sent).  Otherwise returns the receiver. 
  Note that you can pause a MKConductor object before a performance
  begins.  You cannot pause a MKConductor that is synchronizing to
  MIDI time code.  An attempt to do so is ignored.
*/
- pause; 

/*!
  @param  seconds is a double.
  @return Returns an id.
  @brief A convenience method.

  Pauses the performance of the receiver, sends
  <b>hasPaused:</b> to its delegate, and schedules a request for
  <b>resume</b> to be sent to the receiver in <i>seconds</i> seconds. 
  If the receiver is currently paused through a previous invocation of
  this method, the current <b>resume</b> request supercedes the
  previous one.  The effect is restricted to the present performance. 
  You can't pause the clockConductor; returns <b>nil</b> in this case
  (and the delegate message isn't sent).  Otherwise returns the
  receiver.  Note that you can invoke this method before a performance
  begins; the <b>resume</b> message is enqueued to be sent
  <i>seconds</i> seconds after the performance starts.
*/
- pauseFor: (double) seconds;

/*!
  @return Returns an id.
  @brief Resumes the receiver's performance and returns the receiver.

  If the
  receiver isn't currently paused, this has no effect.
*/
- resume; 

/*!
  @param  newBeatSize is a double.
  @return Returns a double.
  @brief Sets the tempo by changing the size of a beat to <i>newBeatSize</i>,
  measured in seconds.

  The default beat size is 1.0 (one second). 
  Attempts to set the tempo of the clockConductor are ignored. 
  Returns the previous beat size.
*/
- (double) setBeatSize: (double) newBeatSize; 

/*!
  @return Returns a double.
  @brief Returns the size of the receiver's beat in seconds.

  
*/
- (double) beatSize; 

/*!
  @param  newTempo is a double.
  @return Returns a double.
  @brief Sets the receiver's tempo to <i>newTempo</i>, measured in beats per
  minute.

  Attempts to set the tempo of the clockConductor are
  ignored.  Returns the previous tempo.
*/
-(double) setTempo: (double) newTempo; 

/*!
  @return Returns a double.
  @brief Returns the receiver's tempo in beats per minute.

  
*/
- (double) tempo; 

/*!
  @brief Sets the receiver's performance time offset to <i>newTimeOffset</i>
  seconds.

  Keep in mind that since the offset is measured in seconds,
  it's not affected by the receiver's tempo.  Attempts to set the
  offset of the clockConductor are ignored. Returns the previous time
  offset.
 @param  newTimeOffset is a double.
 @return Returns a double.
*/
- (double) setTimeOffset: (double) newTimeOffset; 

/*!
  @return Returns a double.
  @brief Returns the receiver's performance time offset in seconds.
*/
- (double) timeOffset; 

/*!
  @brief Places, in the receiver's message request queue, a request for
  <i>aSelector</i> to be sent to <i>toObject</i> at time <i>beats</i>
  beats from the receiver's notion of the current time.

  To ensure
  that the receiver's notion of time is up to date, you should send
  <b>lockPerformance</b> before invoking this method and
  <b>unlockPerformance</b>afterwards.   <i>argCount</i>  specifies the
  number of four-byte arguments to <i>aSelector</i> followed by the
  arguments themselves, seperated by commas (two arguments,
  maximum).
 @param  aSelector is a SEL.
 @param  toObject is an id.
 @param  beats is a double.
 @param  argCount,... is an int counting variable arguments.
 @return Returns an id.
 */
- sel: (SEL) aSelector to: toObject withDelay: (double) beats argCount: (int) argCount, ...;

/*!
  @brief Places, in the receiver's message request queue, a request for
  <i>aSelector</i> to be sent to <i>toObject</i> at time <i>beats</i>
  beats from the receiver's notion of the current time.

  To ensure that the receiver's notion of time is up to date, you should send
  <b>lockPerformance</b> before invoking this method and
  <b>unlockPerformance</b>afterwards.   <i>argCount</i>  specifies the
  number of four-byte arguments to <i>aSelector</i>. If arg1 or arg2 are
  objects, set the retain: argument following them to TRUE to prevent
  the object from any chance of deallocation between this method being
  called, and the message being dispatched.
  @param  aSelector is a SEL.
  @param  toObject is an id.
  @param  beats is a double.
  @param  argCount is an int
  @param  arg1 is an id or any 4-byte data type
  @param  retainArg1 is a BOOL
  @param  arg2 is an id or any 4-byte data type
  @param  retainArg2 is a BOOL
  @return Returns an id.
 */
- (id) sel: (SEL) aSelector
	to: (id) toObject
 withDelay: (double) beats
  argCount: (int) argCount
      arg1: (id) arg1 
    retain: (BOOL) retainArg1
      arg2: (id) arg2 
    retain: (BOOL) retainArg2;

/*!
  @brief Places, in the receiver's message request queue, a request for
  <i>aSelector</i> to be sent to <i>toObject</i> at time <i>time</i>
  beats from the beginning of the receiver's performance.

  <i>argCount</i> specifies the number of four-byte arguments to
  <i>aSelector</i> followed by the arguments themselves, seperated by
  commas (two arguments, maximum). 
 @param  aSelector is a SEL.
 @param  toObject is an id.
 @param  time is a double.
 @param  argCount,... is an int counting variable arguments.
 @return Returns an id.
 */
- sel: (SEL) aSelector to: toObject atTime: (double) time argCount: (int) argCount, ...;

/*!
  @brief Places, in the receiver's message request queue, a request for
  <i>aSelector</i> to be sent to <i>toObject</i> at time <i>time</i>
  beats from the beginning of the receiver's performance.

  <i>argCount</i> specifies the number of four-byte arguments to
  <i>aSelector</i>. If arg1 or arg2 are
	  objects, set the retain: argument following them to TRUE to prevent
	  the object from any chance of deallocation between this method being
	  called, and the message being dispatched.
 @param  aSelector is a SEL.
 @param  toObject is an id.
 @param  time is a double.
 @param  argCount,... is an int
 @param  arg1 is an object or any 4-byte type
 @param  retainArg1 is a BOOL
 @param  arg2 is an object or any 4-byte type
 @param  retainArg2 is a BOOL
 @return Returns an id.
 
 */
-    sel: (SEL) aSelector 
      to: (id) toObject 
  atTime: (double) time
argCount: (int) argCount
    arg1: (id) arg1 
  retain: (BOOL) retainArg1
    arg2: (id) arg2 
  retain: (BOOL) retainArg2;
/*!
  @brief Same as <tt>[[MKConductor clockConductor] time]</tt>.
  
  Returns the current performance time, in seconds.  This doesn't
  include time that the performance has been paused, nor does it
  include the performance's delta time.  If a performance isn't in
  progress, MK_NODVAL is returned .  Use <b>MKIsNoDVal()</b> to check
  for this return value.
 @return Returns a double.
*/
+ (double) timeInSeconds; 

/*!
  @brief Returns the receiver's notion of the current time in
  beats.
  @return Returns a double.
*/
- (double) timeInBeats; 

/*!
  @brief Removes all message requests from the receiver's message request
  queue and returns the receiver.

  Doesn't send any of the messages.
 @return Returns an id.
*/
- emptyQueue; 

/*!
  @brief Returns <b>YES</b> if the receiver is currently sending a message
  from its message request queue.
 @return Returns a BOOL.
*/
- (BOOL) isCurrentConductor;

/*!
  @param  aSelector is a SEL.
  @param  toObject is an id.
  @param  argCount,... is an int.
  @return Returns a MKMsgStruct *.
  @brief Enqueues a request for <i>aSelector</i> to be sent to
  <i>toObject</i> immediately after the current (or next) performance
  ends.

  <i>argCount</i> specifies the number of four-byte arguments
  to <i>aSelector</i> followed by the arguments themselves, separated
  by commas (two arguments, maximum).  You can enqueue as many of
  these requests as you want; they're sent in the order that they were
  enqueued.  Returns a pointer to a <i>message request structure that
  can be passed to</i><b> a C function such as MKCancelMsgRequest()</b>.
*/
+ (MKMsgStruct *) afterPerformanceSel: (SEL) aSelector
				   to: (id) toObject
			     argCount: (int) argCount, ...; 

/*!
  @brief Enqueues a request for <i>aSelector</i> to be sent to
  <i>toObject</i> immediately after the current (or next) performance
  ends.

  <i>argCount</i> specifies the number of four-byte arguments
  to <i>aSelector</i>. arg1 and arg2 can be objects or other 4-byte
  object types (eg int). If either is an object, specify retain:TRUE
  for that object, and it will receive retain and release messages, meaning
  that they should not become accidentally deallocated before the message
  containing them as arguments is dispatched.
  You can enqueue as many of
  these requests as you want; they're sent in the order that they were
  enqueued.  Returns a pointer to a <i>message request structure that
  can be passed to</i><b> a C function such as MKCancelMsgRequest()</b>.
 @param  aSelector is a SEL.
 @param  toObject is an id.
 @param  argCount is an int.
 @param  arg1 is an id or any 4-byte type.
 @param  retainArg1 is a BOOL.
 @param  arg2 is an id or any 4-byte type.
 @param  retainArg2 is a BOOL.
 @return Returns a MKMsgStruct *.
 */
+ (MKMsgStruct *) afterPerformanceSel: (SEL) aSelector 
				   to: (id) toObject 
			     argCount: (int) argCount
				 arg1: (id) arg1 
			       retain: (BOOL) retainArg1
				 arg2: (id) arg2
			       retain: (BOOL) retainArg2;

/*!
  @param  aSelector is a SEL.
  @param  toObject is an id.
  @param  argCount,... is an int.
  @return Returns a MKMsgStruct *.
  @brief Enqueues a request for <i>aSelector</i> to be sent to
  <i>toObject</i> at the beginning of the next performance.

  
  <i>argCount</i> specifies the number of four-byte arguments to
  <i>aSelector</i> followed by the arguments themselves, separated by
  commas (two arguments, maximum).  You can enqueue as many of these
  requests as you want; they're sent in the order that they were
  enqueued.  Returns a pointer to a <i>message request structure that
  can be passed to</i><b> a C function such as MKCancelMsgRequest()</b>.
*/
+ (MKMsgStruct *) beforePerformanceSel: (SEL) aSelector to: toObject argCount: (int) argCount, ...; 

/*!
  @brief Enqueues a request for <i>aSelector</i> to be sent to
  <i>toObject</i> at the beginning of the next performance.
  
  <i>argCount</i> specifies the number of four-byte arguments
  to <i>aSelector</i>. arg1 and arg2 can be objects or other 4-byte
  object types (eg int). If either is an object, specify retain:TRUE
  for that object, and it will receive retain and release messages, meaning
  that they should not become accidentally deallocated before the message
  containing them as arguments is dispatched.
  You can enqueue as many of these
  requests as you want; they're sent in the order that they were
  enqueued.  Returns a pointer to a <i>message request structure that
  can be passed to</i><b> a C function such as MKCancelMsgRequest()</b>.
  @param  aSelector is a SEL.
  @param  toObject is an id.
  @param  argCount is an int.
  @param  arg1 is an id or any 4-byte type.
  @param  retainArg1 is a BOOL.
  @param  arg2 is an id or any 4-byte type.
  @param  retainArg2 is a BOOL.
  @return Returns a MKMsgStruct *.
 */
+ (MKMsgStruct *) beforePerformanceSel: (SEL) aSelector
				    to: (id) toObject 
			      argCount: (int) argCount
				  arg1: (id) arg1
				retain: (BOOL) retainArg1
				  arg2: (id) arg2
				retain: (BOOL) retainArg2;

/*!
  @brief Sets the receiver's delegate object to <i>delegate</i> and returns
  the receiver.

  The delegate is sent <b>hasPaused:</b> and
  <b>hasResumed:</b> as the receiver is paused and resumed,
  respectively. 
 @param  delegate is an id.
 @return Returns an id.
*/
- (void) setDelegate: (id) delegate;

/*!
  @brief Returns the receiver's delegate object, as set through the <b>setDelegate:</b> method.
  @return Returns an id.
*/
- delegate;

/*!
  @brief Sets the receiver's delegate object to <i>delegate</i> and returns
  the receiver.

  The delegate is sent <b>hasPaused:</b> and
  <b>hasResumed:</b> as the receiver is paused and resumed,
  respectively. 
  @param  delegate is an id.
  @return Returns an id.
*/
+ (void) setDelegate: (id) delegate;

/*!
  @brief Returns the receiver's delegate object, as set through the
  <b>setDelegate:</b> method.
 @return Returns an id.
*/
+ delegate;

/*!
  @brief Returns a List of currently active Performers that are assigned to
  this MKConductor.

  The NSMutableArray is <i>not</i> copied and
  should not be freed or altered.
 @return Returns an id.
*/
- activePerformers;

- (void) encodeWithCoder: (NSCoder *) aCoder;
- (id) initWithCoder: (NSCoder *) aDecoder;
- awakeAfterUsingCoder: (NSCoder *) aDecoder;

/* Obsolete methods */
- (double) predictTime:(double)beatTime; 

@end

@interface MKConductor(MTC)

/*!
  @param  aMidiObj is an id.
  @return Returns an id.
  @brief Sets the MKConductor to synchronize to MIDI time code coming in on
  the specified MIDI object.

  Keep in mind that only one MKConductor
  at a time may have an MTCSynch object.   Unclocked performances
  involving MIDI time code conductors are not
	  supported. Hence, <b>setMTCSynch:</b> sends
	  <tt>[MKConductor setClocked:YES];</tt>.  For
  details, see 
<a href=http://www.musickit.org/MusicKitConcepts/miditimecode.html>
Appendix entitled MIDI Time Code in the MusicKit
</a> mentioned above.
*/
- setMTCSynch: (MKMidi *) aMidiObj;

/*!
  @return Returns an id.
  @brief Returns the MKMidi object previously set with <b>setMTCSynch:</b>, or
  <b>nil</b> if none.

  Keep in mind that only one MKConductor at a
  time may have an MTCSynch object.
*/
- (MKMidi *) MTCSynch;

/*!
  @return Returns a double.
  @brief A convenience method.

  Returns the current clock time for the
  object.  If the object is synchronizing to MIDI time code, the value
  returned is the current MIDI time code time, the same value returned
  by MKMidi's <b>time</b> method.   If the object is not synchronizing
  to MIDI time code, the value returend is the same value as the value
  returned by  <tt>[[MKConductor clockConductor] time]</tt>.
*/
- (double) clockTime;

@end

@interface MKConductor(SeparateThread)  <SndDelegateMessagePassing>

/*!
  @param  yesOrNo is a BOOL.
  @return Returns an id.
  @brief If invoked with an argument of YES, all following performances will
  be run in a separate Mach thread.

  Some restrictions apply to
  separate-threaded performances as follows:  You may not do any
  drawing or appkit calls from the separate thread.  If you need to
  send a message to the appkit, use <b>+sendMsgToApplicationThreadSel:
  to:argCount:</b>.  
  
  Default is NO.  You should not send this message if any MKMidi objects are open (or running or stopped. ) 
  
*/
+ useSeparateThread: (BOOL) yesOrNo;

/*!
  @function separateThreaded
  @brief Returns YES if the MKConductor is separate threaded, NO if it runs in the application thread.

  
*/
+ (BOOL) separateThreaded;

/*!
  @brief Returns YES if the MKConductor is separate threaded and the calling code is running
  in the separate thread, NO if the code is running in the application thread.

  
*/
+ (BOOL) separateThreadedAndInMusicKitThread;

/*!
  @return Returns an id.
  @brief In a separate-threaded performance, this method gets the MusicKit
  lock, then sends <b>[MKConductor adjustTime]</b>.

  
  <b>lockPerformance</b> may be called multiple times -- e.g. if you
  lock twice you must unlock twice to give up the lock.  In a
  performance that is not separate-threaded, this method is the same
  as <b>+adjustTime</b>. 
  
  <b>lockPerformanceNoBlock</b>
  <b>+ </b>(BOOL)<b>lockPerformanceNoBlock</b>
  
  Same as lockPerformance but does not wait and returns NO if the lock is  unavailable.  If the lock is successful, sends <b>[MKConductor adjustTime]</b> and returns YES. You rarely use this method.  It is provided for cases where you would prefer to give up than to wait (e.g. when simultaneously doing graphic animation.)
*/
+ lockPerformance;

/*!
  @return Returns an id.
  @brief Undoes lockPerformance.

  In a separate-threaded performace, sends
  <b>[MKOrchestra flushTimedMessages]</b> and then gives up the
  MusicKit lock.  In a performance that is not separate-threaded, this
  method is the same as MKOrchestra's <b>flushTimedMessages</b>,
  except that the flush is done only when the last recursive lock is
  given up (See MKOrchestra.h.)
*/
+ unlockPerformance;

/*!
  @return Returns a BOOL.
  @brief Same as lockPerformance but does not wait and returns NO if the lock
  is  unavailable.

  If the lock is successful, sends <b>[MKConductor
  adjustTime]</b> and returns YES. You rarely use this method.  It is
  provided for cases where you would prefer to give up than to wait
  (e.g. when simultaneously doing graphic animation.)
*/
+ (BOOL) lockPerformanceNoBlock;

/*!
  @param  priorityFactor is a float.
  @return Returns an id.
  @brief This method sets the thread priority of the following and all
  subsequent performances.

  The priority change takes effect when the
  <b>startPerformance</b> method is invoked and is set back to its
  original value in the <b>finishPerformance</b> method.  In a
  separate-threaded performance, the thread that is affected is the
  performance thread.  In the case of a performance that is not
  separate-threaded, the thread affected is the one that invoked the
  <b>startPerformance</b> method.
  
  Priority is specified as a "priorityFactor" between
  0.0 and 1.0.  1.0 corresponds to the maximum priority of a user
  process, 0.0 corresponds to the base priority. The default value is
  0.0.
  
  In addition, if priorityFactor is greater than 0, the
  MusicKit uses Mach's "fixed priority thread scheduling policy". 
  (See the Mach documentation for details on thread scheduling
  policies. )  This scheduling policy is more advantageous for
  real-time processes than  the ordinary time sharing policy.
  
*/
+ setThreadPriority: (float) priorityFactor;

/*!
  @return Returns an NSThread..
  @brief In a separate-threaded MusicKit performance, returns the NSThread
  used in that performance.

  When the thread has exited, returns
  nil. 
*/
+ (NSThread *) performanceThread;

/*!  
  @return returns an id.
  @param  aSelector is a SEL.
  @param  toObject is an id.
  @param  argCount is an integer.
  @param  variable arguments.
  @brief If called from the MusicKit thread, sends an Objective-C
  message from the MusicKit thread to the Application's
  main thread.

  This is the only safe way to invoke the
  Application Kit from within the MusicKit's thread.  The
  message will be run in the application as soon as the
  Application event loop threshold is NX_BASETHRESHOLD. To
  increase the priority of MusicKit-sent messages, use
  <b>+setInterThreadThreshold:</b>.  If called from the
  Application Kit thread, or there is no separate-threaded
  performance going on, this is the same as sending
  aSelector directly to toObject.
*/
+ sendMsgToApplicationThreadSel: (SEL) aSelector to: (id) toObject argCount: (int) argCount, ...;

/*!
  @return
  @brief Called by +initialize to detach a thread to handle messaging between
  any background thread and the application thread.

  It is imperative that
  +initialize is called from the application thread. In effect, this means
  that the very first use of [MKConductor ...] must be done in the
  application thread.
*/
+ (void) detachDelegateMessageThread;

/*!  
  @return none
  @param  target is an id.
  @param  aSelector is a SEL.
  @param  arg1 is any 4-byte argument.
  @param  arg2 is any 4-byte argument.
  @param  count is an integer.
  @brief This is the back end to sendMsgToApplicationThreadSel, above.

  
  It relies on the delegate message thread having been set up
  which is done from +initialize.
*/
+ (void) sendMessageInMainThreadToTarget: (id) target 
                                     sel: (SEL) aSelector
                                    arg1: (id) arg1
                                    arg2: (id) arg2
                                   count: (int) count;

/*!
  @param  newThreshold is an NSString.
  @return Returns an id.
  @brief Resets the threshold used for interthread
  communication.

  This message may only be sent from the Application
  thread.  Otherwise, it is ignored.
*/
+ setInterThreadThreshold: (NSString *) newThreshold;

/*!
  @param  mesg is an NSInvocation, but cast as an unsigned long so the runtime does
  not interpret it as an object, and mangle it (yes the casting has an
  effect at runtime in this situation!).
  @return void.
  @brief This is the method called in the application thread to actually deliver
  the message sent through form the background thread (eg background
  MKConductor thread).

  
*/
+ (void) _sendDelegateInvocation: (in unsigned long) mesg;

@end

#import "MKConductorDelegate.h"

#ifdef __cplusplus
}
#endif

#endif

About Koders | Resources | Downloads | Support | Black Duck | Submit Project | Terms of Service | DMCA | Privacy Policy | Site Map| Contact Us