summaryrefslogtreecommitdiffstats
path: root/Master/Reference Architectures and Patterns/hjp5/html/k100310.html
blob: c7377940d3fa613af8d648cd8ec6a3d1e66e3d39 (plain)
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
<html>
<head>
<title>
Handbuch der Java-Programmierung, 5. Auflage
</title>
</head>
<body>
<a name="startofbody"></a>
<script language="JavaScript" src="hjp4lib.js">
</script>
<script language="JavaScript">
installKbdHandler("97,#startofbody;101,#endofbody;116,cover.html;122,k100003.html;115,search.html;105,index.html;100,JDKDOCS;112,APIDOCS;104,k100307.html;106,k100309.html;107,k100311.html;108,k100312.html");
</script>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html">&nbsp;Titel&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html">&nbsp;Inhalt&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html">&nbsp;Suchen&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html">&nbsp;Index&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()">&nbsp;DOC&nbsp;</a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100307.html">&nbsp;&lt;&lt;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100309.html">&nbsp;&nbsp;&lt;&nbsp;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100311.html">&nbsp;&nbsp;&gt;&nbsp;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100312.html">&nbsp;&gt;&gt;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()">&nbsp;API&nbsp;</a>
<td align="right">Kapitel 49 - Sound
</table>
<hr>


<!-- Section -->
<a name="sectlevel2id049003"></a>
<h2>49.3 <a name="ixa103588">Midi</a></h2>
<hr>
<ul>
<li><a href="k100310.html#sectlevel2id049003">49.3 Midi</a>
<ul>
<li><a href="k100310.html#sectlevel3id049003001">49.3.1 Was ist Midi?</a>
<li><a href="k100310.html#sectlevel3id049003002">49.3.2 Grundlegende Klassen des Midi-APIs</a>
<li><a href="k100310.html#sectlevel3id049003003">49.3.3 Alle meine Entchen - Erster Versuch</a>
<li><a href="k100310.html#sectlevel3id049003004">49.3.4 Alle meine Entchen mit dem Sequenzer</a>
<li><a href="k100310.html#mididateien">49.3.5 Zugriff auf Midi-Dateien</a>
<ul>
<li><a href="k100310.html#sectlevel4id049003005001">Lesen und Abspielen einer Midi-Datei</a>
<li><a href="k100310.html#sectlevel4id049003005002">Abspeichern einer Sequenz in einer Midi-Datei</a>
</ul>
</ul>
</ul>
<hr>


<!-- Section -->
<a name="sectlevel3id049003001"></a>
<h3>49.3.1 Was ist Midi? </h3>

<p>
In den siebziger Jahren standen Musiker, die sich mit elektronischer
Musik besch&auml;ftigten, vor einigen Herausforderungen. Zwar gab
es gut klingende Synthesizer, die unz&auml;hlige Sounds und Erweiterungsm&ouml;glichkeiten
boten. Doch schwierig wurde es, wenn zwei von ihnen miteinander verbunden
werden sollten. Es gab n&auml;mlich keinen einheitlichen Standard
zur &Uuml;bertragung der Daten zwischen den Systemen. Mit den ersten
digitialen Synthesizern der 80er Jahre wurde dieses Problem durch
die Schaffung des <i>Midi</i>-Standards behoben. Midi steht f&uuml;r
<i>Musical Instrument Digital Interface</i> und bezeichnet einen Standard,
der die &Uuml;bertragung von Daten zwischen zwei oder mehr elektronischen
Musikinstrumenten beschreibt. Neben der Standardisierung der Hardware
(Kabel und Stecker) wurde dabei insbesondere festgelegt, welche Daten
&uuml;bertragen und wie sie kodiert werden sollten. 

<p>
Midi war urspr&uuml;nglich eine serielle Schnittstelle, auf der die
Daten byteweise &uuml;bertragen werden. Dr&uuml;ckte der Musiker auf
seinem Keyboard die Taste C, wurde diese Information in eine drei
Byte lange Nachricht verpackt (Status-/Kanalinformation, Tonh&ouml;he,
Lautst&auml;rke) und in Echtzeit an die angeschlossenen Synthesizer
verschickt. Auch beim Loslassen der Taste wurde eine entsprechende
Nachricht verschickt. Die angeschlossenen Synthesizer wurden also
&uuml;ber die Midi-Schnittstelle <i>ferngesteuert</i>. Neben Notendaten
k&ouml;nnen dabei auch Statusinformationen und Einstellungen von Reglern
(Lautst&auml;rke, Effekte, Pitch-Bend etc.) &uuml;bertragen werden.
Auch die &Uuml;bertragung propriet&auml;rer Daten ist vorgesehen,
um die Kommunikation nichtstandardisierter, ger&auml;tespezifischer
Informationen in kontrollierter Weise zu erm&ouml;glichen. 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>

<p>
Es ist wichtig zu verstehen, dass beim Midi-Protokoll nicht die Audiosignale
an sich &uuml;bertragen werden, sondern lediglich die Ereignisse,
die zur ihrer Entstehung f&uuml;hren. Midi-Daten k&ouml;nnen also
in einem gewissen Sinne als die Partitur eines St&uuml;ckes angesehen
werden. Was dann tats&auml;chlich erklingt, wird durch die dadurch
angesteuerten Synthesizer und ihre klanglichen Eigenschaften bestimmt.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
<tr>
<td><font color="#FFFFFF">&nbsp;Hinweis&nbsp;</font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
</tr>
</table>

<p>
Zun&auml;chst war Midi ein reines &#187;Wire&#171;-Protokoll, das
die &Uuml;bertragung von Echtzeit-Daten &uuml;ber eine elektrische
Verbindung beschrieb. Sp&auml;ter wollte man Midi-Datenstr&ouml;me
auch aufzeichnen und in Dateien speichern k&ouml;nnen, und man entwickelte
dazu die Midi-Dateiprotokolle. Darin werden die eigentlichen Midi-Nachrichten
mit <i>Zeitstempeln</i> versehen, um sie sp&auml;ter mit Hilfe eines
<a name="ixa103589"><i>Sequenzers</i></a> in ihrer exakten zeitlichen
Abfolge wiedergeben zu k&ouml;nnen. Im Sound-API werden Midi-Daten
ohne Zeitstempel als <a name="ixa103590"><i>Midi-Nachrichten</i></a>
(<i>Midi-Messages</i>) und solche mit Zeitstempel als <a name="ixa103591"><i>Midi-Ereignisse</i></a>
(<i>Midi-Events</i>) bezeichnet. Der Inhalt einer Midi-Datei wird
&uuml;blicherweise als <a name="ixa103592"><i>Sequenz</i></a> bezeichnet.
Eine Sequenz enth&auml;lt eine Reihe von <i>Spuren</i>, die ihrerseits
die Midi-Events enthalten. Meist repr&auml;sentieren die Spuren die
unterschiedlichen Instrumente eines St&uuml;cks, so dass etwa in Spur
eins das Piano liegt, in Spur zwei der Bass usw. Die verschiedenen
Spuren werden innerhalb der Midi-Events durch <i>Kan&auml;le</i> repr&auml;sentiert,
von denen es maximal 16 pro Midi-Schnittstelle gibt. 

<!-- Section -->

<a name="sectlevel3id049003002"></a>
<h3>49.3.2 Grundlegende Klassen des Midi-APIs </h3>

<p>
&Auml;hnlich wie im Sampling-API gibt es eine Reihe von Klassen und
Interfaces, mit denen die zuvor beschriebenen Konzepte innerhalb des
Midi-APIs umgesetzt werden. Sie befinden sich im zweiten gro&szlig;en
Bestandteil des Java Sound-APIs, dem Paket <a name="ixa103593"><a href="index_j.html#ixb102701"><font color=#000080><tt>javax.sound.midi</tt></font></a></a>.
Wir wollen die wichtigsten von ihnen kurz vorstellen: 
<ul>
<li>Analog zur Klasse <a href="index_a.html#ixb102658"><font color=#000080><tt>AudioSystem</tt></font></a>
gibt es im Paket <a href="index_j.html#ixb102701"><font color=#000080><tt>javax.sound.midi</tt></font></a>
eine Klasse <a name="ixa103594"><a href="index_m.html#ixb102702"><font color=#000080><tt>MidiSystem</tt></font></a></a>,
mit der Midi-Ger&auml;te und Midi-Dateien beschafft und Informationen
&uuml;ber sie abgefragt werden k&ouml;nnen.
<li>Ein Midi-Ger&auml;t wird durch die Klasse <a name="ixa103595"><a href="index_m.html#ixb102703"><font color=#000080><tt>MidiDevice</tt></font></a></a>
repr&auml;sentiert. Ein <a href="index_m.html#ixb102703"><font color=#000080><tt>MidiDevice</tt></font></a>
kann entweder ge&ouml;ffnet oder geschlossen sein und besitzt eine
Reihe von Ein- und Ausgabeelementen. Die Eingabeelemente werden durch
das Interface <a name="ixa103596"><a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a></a>,
die Ausgabeelemente durch das Interface <a name="ixa103597"><a href="index_t.html#ixb102705"><font color=#000080><tt>Transmitter</tt></font></a></a>
dargestellt. Ein <a href="index_m.html#ixb102703"><font color=#000080><tt>MidiDevice</tt></font></a>
kennt die Anzahl seiner <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
und <a href="index_t.html#ixb102705"><font color=#000080><tt>Transmitter</tt></font></a>
und stellt diese auf Anfrage zur Verf&uuml;gung.
<li>Die wichtigsten Unterklassen von <a href="index_m.html#ixb102703"><font color=#000080><tt>MidiDevice</tt></font></a>
sind <a name="ixa103598"><a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a></a>
und <a name="ixa103599"><a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a></a>.
Gegen&uuml;ber seiner Vaterklasse besitzt ein <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
zus&auml;tzlich Informationen &uuml;ber die verf&uuml;gbaren Instrumente
und ihre Zuordnung auf die verschiedenen Kan&auml;le. Ein <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
besitzt dagegen Methoden, um eine Sequenz abzuspielen oder anzuhalten
und Parameter wie Tempo, Synchronisierung oder Positionierung zu beeinflussen.
<li>Eine Midi-Nachricht wird durch die Klasse <a name="ixa103600"><a href="index_m.html#ixb102708"><font color=#000080><tt>MidiMessage</tt></font></a></a>
und deren Unterklassen <a name="ixa103601"><a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a></a>,
<a name="ixa103602"><a href="index_m.html#ixb102710"><font color=#000080><tt>MetaMessage</tt></font></a></a>
und <a name="ixa103603"><a href="index_s.html#ixb102711"><font color=#000080><tt>SysexMessage</tt></font></a></a>
repr&auml;sentiert. Ein Midi-Ereignis wird durch die Klasse <a name="ixa103604"><a href="index_m.html#ixb102712"><font color=#000080><tt>MidiEvent</tt></font></a></a>
dargestellt, die zus&auml;tzlich zur <a href="index_m.html#ixb102708"><font color=#000080><tt>MidiMessage</tt></font></a>
einen Zeitstempel enth&auml;lt. Eine Sequenz wird durch die Klasse
<a name="ixa103605"><a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a></a>
repr&auml;sentiert. Sie enth&auml;lt neben einigen globalen Informationen
zum Timing der Daten eine Reihe von <a name="ixa103606"><a href="index_t.html#ixb102714"><font color=#000080><tt>Tracks</tt></font></a></a>,
die ihrerseits die <a href="index_m.html#ixb102712"><font color=#000080><tt>MidiEvents</tt></font></a>
enthalten.
</ul>

<p>
Weitere Details zu den genannten Klassen werden in den folgenden Abschnitten
vorgestellt. 

<!-- Section -->

<a name="sectlevel3id049003003"></a>
<h3>49.3.3 Alle meine Entchen - Erster Versuch </h3>

<p>
In diesem Abschnitt wollen wir uns die Aufgabe stellen, das allseits
bekannte &#187;Alle meine Entchen&#171; mit Hilfe des Midi-APIs wiederzugeben.
Zuerst wollen wir einen sehr einfachen Ansatz w&auml;hlen, bei dem
die Midi-Nachrichten in Echtzeit an einen Synthesizer geschickt werden,
wobei das Timing mit Hilfe von <font color="#000077"><tt>Thread.sleep</tt></font>-Aufrufen
manuell gesteuert wird. 

<p>
Zun&auml;chst wird also ein Synthesizer ben&ouml;tigt, den wir von
der Klasse <a href="index_m.html#ixb102702"><font color=#000080><tt>MidiSystem</tt></font></a>
beziehen k&ouml;nnen: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public static Synthesizer getSynthesizer()
  throws MidiUnavailableException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/MidiSystem.html" onClick="this.href=getApiDoc('javax.sound.midi.MidiSystem')"><font color="#660066" size=-1>javax.sound.midi.MidiSystem</font></a></td>
</tr>
</table>

<p>
<a name="ixa103607"><a href="index_g.html#ixb102715"><font color=#000080><tt>getSynthesizer</tt></font></a></a>
liefert den Default-Synthesizer der installierten Sound-Hardware,
typischerweise den auf der Soundkarte eingebauten. Ist mehr als ein
Synthesizer vorhanden, muss die Liste aller verf&uuml;gbaren Synthesizer
durch Aufruf von <a name="ixa103608"><a href="index_g.html#ixb102716"><font color=#000080><tt>getMidiDeviceInfo</tt></font></a></a>
durchsucht und mit <a name="ixa103609"><a href="index_g.html#ixb102717"><font color=#000080><tt>getMidiDevice</tt></font></a></a>
der gew&uuml;nschte ausgew&auml;hlt werden. Wir wollen zun&auml;chst
davon ausgehen, dass ein Default-Synthesizer vorhanden ist, der unseren
Anspr&uuml;chen gen&uuml;gt. 

<p>
Nachdem der <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
verf&uuml;gbar ist, muss er ge&ouml;ffnet und zur &Uuml;bergabe von
Midi-Nachrichten ein <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
beschafft werden: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public void open()
  throws MidiUnavailableException

public void close()

public boolean isOpen()

public int getMaxReceivers()

public Receiver getReceiver()
  throws MidiUnavailableException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Synthesizer.html" onClick="this.href=getApiDoc('javax.sound.midi.Synthesizer')"><font color="#660066" size=-1>javax.sound.midi.Synthesizer</font></a></td>
</tr>
</table>

<p>
Das &Ouml;ffnen und Schlie&szlig;en eines Midi-Ger&auml;ts wird mit
<a name="ixa103610"><a href="index_o.html#ixb101348"><font color=#000080><tt>open</tt></font></a></a>
und <a name="ixa103611"><a href="index_c.html#ixb100957"><font color=#000080><tt>close</tt></font></a></a>
erledigt, und mit <a name="ixa103612"><a href="index_i.html#ixb102718"><font color=#000080><tt>isOpen</tt></font></a></a>
kann sein aktueller Status herausgefunden werden. Ein <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
kann durch Aufruf von <a name="ixa103613"><a href="index_g.html#ixb102719"><font color=#000080><tt>getReceiver</tt></font></a></a>
beschafft werden, die Gesamtzahl aller vorhandenen <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
kann mit <a name="ixa103614"><a href="index_g.html#ixb102720"><font color=#000080><tt>getMaxReceivers</tt></font></a></a>
abgefragt werden. 

<p>
Um an ein Midi-Ger&auml;t Daten zu senden, werden diese einfach an
einen seiner <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
geschickt. Dazu besitzt dieser eine Methode <a name="ixa103615"><a href="index_s.html#ixb102721"><font color=#000080><tt>send</tt></font></a></a>,
an die beim Aufruf die gew&uuml;nschte <a href="index_m.html#ixb102708"><font color=#000080><tt>MidiMessage</tt></font></a>
&uuml;bergeben wird: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public void send(MidiMessage message, long timeStamp)
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Receiver.html" onClick="this.href=getApiDoc('javax.sound.midi.Receiver')"><font color="#660066" size=-1>javax.sound.midi.Receiver</font></a></td>
</tr>
</table>

<p>
Das zweite Argument <font color="#000077"><tt>timeStamp</tt></font>
ist zur Feinsynchronisierung der Midi-Nachrichten vorgesehen. Damit
soll ein <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
in der Lage sein, <i>leichte</i> Timing-Schwankungen beim Anliefern
der Daten auszugleichen. Ob ein Ger&auml;t dieses Feature unterst&uuml;tzt,
kann durch Aufruf von <a name="ixa103616"><a href="index_g.html#ixb102722"><font color=#000080><tt>getMicrosecondPosition</tt></font></a></a>
bestimmt werden. Ist dessen R&uuml;ckgabewert -1, werden derartige
Timestamps nicht unterst&uuml;tzt: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public long getMicrosecondPosition()
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/MidiDevice.html" onClick="this.href=getApiDoc('javax.sound.midi.MidiDevice')"><font color="#660066" size=-1>javax.sound.midi.MidiDevice</font></a></td>
</tr>
</table>

<p>
Aber auch, wenn diese Timestamps unterst&uuml;tzt werden, sollte man
keine Wunder von ihnen erwarten. Die Spezifikation weist ausdr&uuml;cklich
darauf hin, dass damit nur <i>kleinere</i> Timing-Schwankungen ausgeglichen
werden k&ouml;nnen. Liegt ein Zeitstempel dagegen weit in der Zukunft
(oder gar in der Vergangenheit), ist das Midi-Ger&auml;t nicht verpflichtet,
diesen korrekt zu behandeln. Wird -1 an das <font color="#000077"><tt>timeStamp</tt></font>-Argument
von <a href="index_s.html#ixb102721"><font color=#000080><tt>send</tt></font></a>
&uuml;bergeben, ignoriert das entsprechende Ger&auml;t den Zeitstempel
und bearbeitet die Midi-Nachricht, so schnell es kann. 

<p>
Um eine <a href="index_m.html#ixb102708"><font color=#000080><tt>MidiMessage</tt></font></a>
zu konstruieren, wird diese zun&auml;chst mit <a href="index_n.html#ixb100089"><font color=#000080><tt>new</tt></font></a>
erzeugt und durch Aufruf von <a name="ixa103617"><a href="index_s.html#ixb102723"><font color=#000080><tt>setMessage</tt></font></a></a>
mit Daten gef&uuml;llt. Da wir weder Meta- noch Sysex-Daten ben&ouml;tigen,
wollen wir uns lediglich die Konstruktion einer <a name="ixa103618"><a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a></a>
mit Hilfe der folgenden <a href="index_s.html#ixb102723"><font color=#000080><tt>setMessage</tt></font></a>-Methode
ansehen: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public void setMessage(
  int command,
  int channel,
  int data1,
  int data2
)
  throws InvalidMidiDataException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/ShortMessage.html" onClick="this.href=getApiDoc('javax.sound.midi.ShortMessage')"><font color="#660066" size=-1>javax.sound.midi.ShortMessage</font></a></td>
</tr>
</table>

<p>
Als erstes Argument muss das gew&uuml;nschte Midi-Kommando &uuml;bergeben
werden. Die f&uuml;r uns relevanten Kommandos sind <a name="ixa103619"><a href="index_n.html#ixb102724"><font color=#000080><tt>NOTE_ON</tt></font></a></a>
(Taste wird gedr&uuml;ckt), <a name="ixa103620"><a href="index_n.html#ixb102725"><font color=#000080><tt>NOTE_OFF</tt></font></a></a>
(Taste wird losgelassen) und <a name="ixa103621"><a href="index_p.html#ixb102726"><font color=#000080><tt>PROGRAM_CHANGE</tt></font></a></a>
(Instrumentenwechsel). Sie werden als Konstanten in der Klasse <a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a>
definiert. Als zweites Argument wird der Kanal angegeben, auf den
sich das Kommando auswirken soll. Anschlie&szlig;end folgen zwei Datenbytes,
die kommandospezifisch sind. Das <a href="index_n.html#ixb102724"><font color=#000080><tt>NOTE_ON</tt></font></a>-Kommando
erwartet darin beispielsweise die Tonh&ouml;he (die verf&uuml;gbaren
Noten sind als Ganzzahlen durchnummeriert) und die relative Lautst&auml;rke
(Anschlagsdynamik) der Note. <a href="index_n.html#ixb102725"><font color=#000080><tt>NOTE_OFF</tt></font></a>
erwartet die Tonh&ouml;he als erstes Datenbyte und ignoriert das zweite.
<a href="index_p.html#ixb102726"><font color=#000080><tt>PROGRAM_CHANGE</tt></font></a>
erwartet die gew&uuml;nschte Programmnummer und ignoriert das zweite
Datenbyte. 

<p>
Nach diesen Vorbemerkungen wollen wir uns nun ein Beispielprogramm
ansehen: 
<a name="ame1"></a>

<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#00AA00">/* Listing4902.java */</font>
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">import</font> javax.sound.midi.*;
<font color="#555555">004 </font>
<font color="#555555">005 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing4902
<font color="#555555">006 </font>{
<font color="#555555">007 </font>  <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#006699">void</font> playAlleMeineEntchen()
<font color="#555555">008 </font>  <font color="#0000AA">throws</font> Exception
<font color="#555555">009 </font>  {
<font color="#555555">010 </font>    <font color="#00AA00">//Partitur {{Tonhoehe, DauerInViertelNoten, AnzahlWdh},...}</font>
<font color="#555555">011 </font>    <font color="#0000AA">final</font> <font color="#006699">int</font> DATA[][] = { <a name="ame1.a"></a>
<font color="#555555">012 </font>      {60,  1, 1}, <font color="#00AA00">//C</font>
<font color="#555555">013 </font>      {62,  1, 1}, <font color="#00AA00">//D</font>
<font color="#555555">014 </font>      {64,  1, 1}, <font color="#00AA00">//E</font>
<font color="#555555">015 </font>      {65,  1, 1}, <font color="#00AA00">//F</font>
<font color="#555555">016 </font>      {67,  2, 2}, <font color="#00AA00">//G,G</font>
<font color="#555555">017 </font>      {69,  1, 4}, <font color="#00AA00">//A,A,A,A</font>
<font color="#555555">018 </font>      {67,  4, 1}, <font color="#00AA00">//G</font>
<font color="#555555">019 </font>      {69,  1, 4}, <font color="#00AA00">//A,A,A,A</font>
<font color="#555555">020 </font>      {67,  4, 1}, <font color="#00AA00">//G</font>
<font color="#555555">021 </font>      {65,  1, 4}, <font color="#00AA00">//F,F,F,F</font>
<font color="#555555">022 </font>      {64,  2, 2}, <font color="#00AA00">//E,E</font>
<font color="#555555">023 </font>      {62,  1, 4}, <font color="#00AA00">//D,D,D,D</font>
<font color="#555555">024 </font>      {60,  4, 1}  <font color="#00AA00">//C</font>
<font color="#555555">025 </font>    };
<font color="#555555">026 </font>    <font color="#00AA00">//Synthesizer &ouml;ffnen und Receiver holen</font>
<font color="#555555">027 </font>    Synthesizer synth = MidiSystem.getSynthesizer(); <a name="ame1.b"></a>
<font color="#555555">028 </font>    synth.open();
<font color="#555555">029 </font>    Receiver rcvr = synth.getReceiver();
<font color="#555555">030 </font>    <font color="#00AA00">//Melodie spielen</font>
<font color="#555555">031 </font>    ShortMessage msg = <font color="#0000AA">new</font> ShortMessage();
<font color="#555555">032 </font>    <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 0; i &lt; DATA.length; ++i) {
<font color="#555555">033 </font>      <font color="#0000AA">for</font> (<font color="#006699">int</font> j = 0; j &lt; DATA[i][2]; ++j) { <font color="#00AA00">//Anzahl Wdh. je Note</font>
<font color="#555555">034 </font>        <font color="#00AA00">//Note an</font>
<font color="#555555">035 </font>        msg.setMessage(ShortMessage.NOTE_ON, 0, DATA[i][0], 64);
<font color="#555555">036 </font>        rcvr.send(msg, -1);
<font color="#555555">037 </font>        <font color="#00AA00">//Pause</font>
<font color="#555555">038 </font>        <font color="#0000AA">try</font> {
<font color="#555555">039 </font>          Thread.sleep(DATA[i][1] * 400); <a name="ame1.c"></a>
<font color="#555555">040 </font>        } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">041 </font>          <font color="#00AA00">//nothing</font>
<font color="#555555">042 </font>        }
<font color="#555555">043 </font>        <font color="#00AA00">//Note aus</font>
<font color="#555555">044 </font>        msg.setMessage(ShortMessage.NOTE_OFF, 0, DATA[i][0], 0);
<font color="#555555">045 </font>        rcvr.send(msg, -1);
<font color="#555555">046 </font>      }
<font color="#555555">047 </font>    }
<font color="#555555">048 </font>    <font color="#00AA00">//Synthesizer schlie&szlig;en</font>
<font color="#555555">049 </font>    synth.close();
<font color="#555555">050 </font>  }
<font color="#555555">051 </font>
<font color="#555555">052 </font>  <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
<font color="#555555">053 </font>  {
<font color="#555555">054 </font>    <font color="#0000AA">try</font> {
<font color="#555555">055 </font>      playAlleMeineEntchen();
<font color="#555555">056 </font>    } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">057 </font>      e.printStackTrace();
<font color="#555555">058 </font>      System.exit(1);
<font color="#555555">059 </font>    }
<font color="#555555">060 </font>    System.exit(0);
<font color="#555555">061 </font>  }
<font color="#555555">062 </font>}</pre>
</font>
</td>
<td valign=top align=right>
<a href="../examples/Listing4902.java"><font color="#000055" size=-1>Listing4902.java</font></a></td>
</tr>
</table>
<i>
Listing 49.2: Alle meine Entchen - Erster Versuch</i></p>

<p>
Ab <a href="k100310.html#ame1.b">Zeile 027</a> wird ein <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
aktiviert und zur &Uuml;bergabe von Midi-Nachrichten auf einen seiner
<a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
zugegriffen. Anschlie&szlig;end wird die Melodie durch wiederholten
Aufruf seiner <a href="index_s.html#ixb102721"><font color=#000080><tt>send</tt></font></a>-Methode
abgespielt. Die Melodie ist in dem Array <font color="#000077"><tt>DATA</tt></font>
in <a href="k100310.html#ame1.a">Zeile 011</a> versteckt. F&uuml;r
jede einzelne Note wird dort die Tonh&ouml;he, die Tondauer in Viertelnoten
und die Anzahl der Wiederholungen angegeben. Die jeweilige Noteninformation
wird mit <a href="index_s.html#ixb102723"><font color=#000080><tt>setMessage</tt></font></a>
an die vorinstanzierte <a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a>
&uuml;bergeben und als <font color="#000077"><tt>NOTE_ON</tt></font>-Nachricht
an den Synthesizer geschickt. In <a href="k100310.html#ame1.c">Zeile 039</a>
pausiert das Programm, um die Note entsprechend ihrer L&auml;nge erklingen
zu lassen (in unserem Beispiel 400 ms. je Viertelnote). Anschlie&szlig;end
wird die <font color="#000077"><tt>NOTE_OFF</tt></font>-Nachricht
geschickt, um den Ton zu beenden. 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100%>
<tr>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=1></td>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top width=1000>

<p>
Wenn wir das Programm mit dem Java-Interpreter starten und eine passende
Sound-Hardware vorhanden ist, h&ouml;ren wir tats&auml;chlich &#187;Alle
meine Entchen&#171;. Bei unver&auml;nderter Standard-Instrumentierung
sollte die Melodie auf einem Klavier gespielt werden. Wenn wir genau
hinh&ouml;ren, stellen wir allerdings ein Problem fest: Das Timing
des St&uuml;cks ist nicht pr&auml;zise, sondern schwankt w&auml;hrend
der Darbietung. Manche Noten werden etwas zu kurz, andere dagegen
zu lang gespielt. Das liegt daran, dass die mit <font color="#000077"><tt>Thread.sleep</tt></font>
erzeugten Notenl&auml;ngen bei weitem nicht pr&auml;zise genug sind.
Die beim Aufruf erzeugten Schwankungen sind f&uuml;r das menschliche
Ohr sehr gut h&ouml;rbar und f&uuml;hren dazu, dass das Musikst&uuml;ck
ungenie&szlig;bar wird. Obwohl das Verfahren <i>prinzipiell</i> funktioniert,
ben&ouml;tigen wir also ein pr&auml;ziseres Wiedergabewerkzeug. Und
das ist das Thema des n&auml;chsten Abschnitts.</td>
<td><img src="trp1_1.gif" width=2></td>
<td valign=top>
<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#CC0000">
<tr>
<td><font color="#FFFFFF">&nbsp;Warnung&nbsp;</font></td>
</tr>
</table>
</td>
<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
</tr>
</table>


<!-- Section -->
<a name="sectlevel3id049003004"></a>
<h3>49.3.4 Alle meine Entchen mit dem Sequenzer </h3>

<p>
Neben dem <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
ist der <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
das zweite wichtige <a href="index_m.html#ixb102703"><font color=#000080><tt>MidiDevice</tt></font></a>.
Er dient dazu, Midi-Sequenzen entsprechend der darin enthaltenen Timing-Information
<i>pr&auml;zise</i> wiederzugeben. Das h&ouml;rt sich zun&auml;chst
einmal einfach an, ist es aber nicht. Einerseits ben&ouml;tigt ein
Sequencer einen Zeitgeber, der genauer ist als die &uuml;blicherweise
vom Betriebssystem zur Verf&uuml;gung gestellten Timer. Zweitens muss
dieser m&ouml;glichst immun gegen Schwankungen der CPU-Last sein,
d.h. der Sequencer sollte auch dann noch stabil arbeiten, wenn im
Hintergrund CPU-intensive Operationen ablaufen. Drittens muss ein
Sequenzer nicht nur, wie in unserem Beispiel, eine einzige Spur mit
verh&auml;ltnism&auml;&szlig;ig langsamen Viertelnoten abspielen,
sondern m&ouml;glicherweise ein Dutzend von ihnen, mit Achteln, Sechzehnteln
oder noch k&uuml;rzeren Noten, wie sie beispielsweise bei Schlagzeugspuren
auftreten. Zudem enthalten die Spuren oft immense Mengen an Controller-Daten
(z.B. Pitch-Bend), die ebenfalls pr&auml;zise wiedergegeben werden
m&uuml;ssen. Zu guter Letzt besitzt ein Sequenzer Zusatzfunktionen,
wie das &Auml;ndern der Abspielgeschwindigkeit, das Ausblenden einzelner
Spuren oder das Synchronisieren mit externen Taktgebern, und er besitzt
in aller Regel einen Aufnahmemodus, mit dem Mididaten in Echtzeit
aufgenommen werden k&ouml;nnen. 

<p>
Wir sehen also, dass die Implementierung eines guten Sequenzers gar
nicht so einfach ist. Gl&uuml;cklicherweise stellt das <a href="index_m.html#ixb102702"><font color=#000080><tt>MidiSystem</tt></font></a>
einen eigenen <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
zur Verf&uuml;gung, dessen Standardimplementierung durch einen Aufruf
von <a name="ixa103622"><a href="index_g.html#ixb102727"><font color=#000080><tt>getSequencer</tt></font></a></a>
beschafft werden kann: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public static Sequencer getSequencer()
  throws MidiUnavailableException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/MidiSystem.html" onClick="this.href=getApiDoc('javax.sound.midi.MidiSystem')"><font color="#660066" size=-1>javax.sound.midi.MidiSystem</font></a></td>
</tr>
</table>

<p>
Beim Abspielen einer Melodie mit dem <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
werden die Midi-Nachrichten nicht mehr direkt an den <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
geschickt, sondern zun&auml;chst in eine <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
verpackt. Diese kann wie folgt konstruiert werden: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public Sequence(float divisionType, int resolution)
  throws InvalidMidiDataException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Sequence.html" onClick="this.href=getApiDoc('javax.sound.midi.Sequence')"><font color="#660066" size=-1>javax.sound.midi.Sequence</font></a></td>
</tr>
</table>

<p>
Das erste Argument gibt die Art und Weise an, wie das Timing erzeugt
werden soll. Hier gibt es im wesentlichen die M&ouml;glichkeiten,
einen internen Timer zu verwenden, der auf Bruchteilen von Viertelnoten
basiert, oder mit externer Synchronisation zu arbeiten, bei der die
Timing-Informationen im <a name="ixa103623"><i>SMPTE-Format</i></a>
zur Verf&uuml;gung gestellt werden. Wir wollen die erste Variante
w&auml;hlen und &uuml;bergeben dazu die Konstante <a name="ixa103624"><a href="index_p.html#ixb102729"><font color=#000080><tt>Sequence.PPQ</tt></font></a></a>
als erstes Argument. Das zweite Argument <font color="#000077"><tt>resoultion</tt></font>
bezieht sich auf das erste und gibt die Aufl&ouml;sung des Timers
an. In unserem Fall w&uuml;rde es also die Anzahl der Zeitimpulse
je Viertelnote angeben. 

<p>
Um eine <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
mit Daten zu f&uuml;llen, wird mindestens ein <a name="ixa103625"><a href="index_t.html#ixb102714"><font color=#000080><tt>Track</tt></font></a></a>
ben&ouml;tigt, der durch Aufruf von <a name="ixa103626"><a href="index_c.html#ixb102730"><font color=#000080><tt>createTrack</tt></font></a></a>
erzeugt werden kann: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public Track createTrack()
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Sequence.html" onClick="this.href=getApiDoc('javax.sound.midi.Sequence')"><font color="#660066" size=-1>javax.sound.midi.Sequence</font></a></td>
</tr>
</table>

<p>
Ein <a href="index_t.html#ixb102714"><font color=#000080><tt>Track</tt></font></a>-Objekt
ist zun&auml;chst leer und wird durch wiederholte Aufrufe von <a name="ixa103627"><a href="index_a.html#ixb100727"><font color=#000080><tt>add</tt></font></a></a>
mit Midi-Ereignissen versehen: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public boolean add(MidiEvent event)
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Track.html" onClick="this.href=getApiDoc('javax.sound.midi.Track')"><font color="#660066" size=-1>javax.sound.midi.Track</font></a></td>
</tr>
</table>

<p>
Nachdem die <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
fertiggestellt ist, kann sie durch Aufruf von <a name="ixa103628"><a href="index_s.html#ixb102731"><font color=#000080><tt>setSequence</tt></font></a></a>
an den <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
&uuml;bergeben werden: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public void setSequence(Sequence sequence)
  throws InvalidMidiDataException

public void setTempoInBPM(float bpm)

public void start()
public void stop()
public boolean isRunning()
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Sequencer.html" onClick="this.href=getApiDoc('javax.sound.midi.Sequencer')"><font color="#660066" size=-1>javax.sound.midi.Sequencer</font></a></td>
</tr>
</table>

<p>
Mit <a name="ixa103629"><a href="index_s.html#ixb102732"><font color=#000080><tt>setTempoInBPM</tt></font></a></a>
kann das Abspieltempo in &#187;Beats Per Minute&#171; (kurz <a name="ixa103630"><i>BPM</i></a>),
also in Viertelnoten pro Minute, angegeben werden. <a name="ixa103631"><a href="index_s.html#ixb101110"><font color=#000080><tt>start</tt></font></a></a>
startet das Abspielen der Sequenz, <a name="ixa103632"><a href="index_s.html#ixb101115"><font color=#000080><tt>stop</tt></font></a></a>
beendet es. Mit <a name="ixa103633"><a href="index_i.html#ixb102692"><font color=#000080><tt>isRunning</tt></font></a></a>
kann gepr&uuml;ft werden, ob der Sequencer gerade l&auml;uft. 

<p>
Bevor eine <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
abgespielt werden kann, m&uuml;ssen <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
und <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
miteinander verbunden werden. Dies geschieht, indem ein <a href="index_t.html#ixb102705"><font color=#000080><tt>Transmitter</tt></font></a>
des Sequenzers an einen <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
des Synthesizers angeschlossen wird. Der <a href="index_t.html#ixb102705"><font color=#000080><tt>Transmitter</tt></font></a>
verf&uuml;gt dazu &uuml;ber eine Methode <a name="ixa103634"><a href="index_s.html#ixb102734"><font color=#000080><tt>setReceiver</tt></font></a></a>,
an die der empfangende <a href="index_r.html#ixb102704"><font color=#000080><tt>Receiver</tt></font></a>
&uuml;bergeben wird: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public void setReceiver(Receiver receiver)
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/Transmitter.html" onClick="this.href=getApiDoc('javax.sound.midi.Transmitter')"><font color="#660066" size=-1>javax.sound.midi.Transmitter</font></a></td>
</tr>
</table>

<p>
Nach diesen Vorbemerkungen k&ouml;nnen wir uns nun ansehen, wie &#187;Alle
meine Entchen&#171; mit Hilfe eines Sequenzers wiedergegeben werden
kann. 
<a name="ame2"></a>

<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#00AA00">/* Listing4903.java */</font>
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">import</font> javax.sound.midi.*;
<font color="#555555">004 </font>
<font color="#555555">005 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing4903
<font color="#555555">006 </font>{
<font color="#555555">007 </font>  <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#006699">void</font> playAlleMeineEntchen()
<font color="#555555">008 </font>  <font color="#0000AA">throws</font> Exception
<font color="#555555">009 </font>  {
<font color="#555555">010 </font>    <font color="#00AA00">//Partitur {{Tonhoehe, DauerInViertelNoten, AnzahlWdh},...}</font>
<font color="#555555">011 </font>    <font color="#0000AA">final</font> <font color="#006699">int</font> DATA[][] = {
<font color="#555555">012 </font>      {60,  1, 1}, <font color="#00AA00">//C</font>
<font color="#555555">013 </font>      {62,  1, 1}, <font color="#00AA00">//D</font>
<font color="#555555">014 </font>      {64,  1, 1}, <font color="#00AA00">//E</font>
<font color="#555555">015 </font>      {65,  1, 1}, <font color="#00AA00">//F</font>
<font color="#555555">016 </font>      {67,  2, 2}, <font color="#00AA00">//G,G</font>
<font color="#555555">017 </font>      {69,  1, 4}, <font color="#00AA00">//A,A,A,A</font>
<font color="#555555">018 </font>      {67,  4, 1}, <font color="#00AA00">//G</font>
<font color="#555555">019 </font>      {69,  1, 4}, <font color="#00AA00">//A,A,A,A</font>
<font color="#555555">020 </font>      {67,  4, 1}, <font color="#00AA00">//G</font>
<font color="#555555">021 </font>      {65,  1, 4}, <font color="#00AA00">//F,F,F,F</font>
<font color="#555555">022 </font>      {64,  2, 2}, <font color="#00AA00">//E,E</font>
<font color="#555555">023 </font>      {62,  1, 4}, <font color="#00AA00">//D,D,D,D</font>
<font color="#555555">024 </font>      {60,  4, 1}  <font color="#00AA00">//C</font>
<font color="#555555">025 </font>    };
<font color="#555555">026 </font>    <font color="#00AA00">//Sequence bauen</font>
<font color="#555555">027 </font>    <font color="#0000AA">final</font> <font color="#006699">int</font> PPQS = 16; <a name="ame2.a"></a>
<font color="#555555">028 </font>    <font color="#0000AA">final</font> <font color="#006699">int</font> STAKKATO = 4;
<font color="#555555">029 </font>    Sequence seq = <font color="#0000AA">new</font> Sequence(Sequence.PPQ, PPQS);
<font color="#555555">030 </font>    Track track = seq.createTrack();
<font color="#555555">031 </font>    <font color="#006699">long</font> currentTick = 0;
<font color="#555555">032 </font>    ShortMessage msg;
<font color="#555555">033 </font>    <font color="#00AA00">//Kanal 0 auf "EnsembleStrings" umschalten</font>
<font color="#555555">034 </font>    msg = <font color="#0000AA">new</font> ShortMessage(); <a name="ame2.e"></a>
<font color="#555555">035 </font>    msg.setMessage(ShortMessage.PROGRAM_CHANGE, 0, 48, 0);
<font color="#555555">036 </font>    track.add(<font color="#0000AA">new</font> MidiEvent(msg, currentTick));
<font color="#555555">037 </font>    <font color="#00AA00">//Partiturdaten hinzuf&uuml;gen</font>
<font color="#555555">038 </font>    <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 0; i &lt; DATA.length; ++i) { <a name="ame2.b"></a>
<font color="#555555">039 </font>      <font color="#0000AA">for</font> (<font color="#006699">int</font> j = 0; j &lt; DATA[i][2]; ++j) { <font color="#00AA00">//Anzahl Wdh. je Note</font>
<font color="#555555">040 </font>        msg = <font color="#0000AA">new</font> ShortMessage();
<font color="#555555">041 </font>        msg.setMessage(ShortMessage.NOTE_ON, 0, DATA[i][0], 64);
<font color="#555555">042 </font>        track.add(<font color="#0000AA">new</font> MidiEvent(msg, currentTick));
<font color="#555555">043 </font>        currentTick += PPQS * DATA[i][1] - STAKKATO;
<font color="#555555">044 </font>        msg = <font color="#0000AA">new</font> ShortMessage();
<font color="#555555">045 </font>        msg.setMessage(ShortMessage.NOTE_OFF, 0, DATA[i][0], 0);
<font color="#555555">046 </font>        track.add(<font color="#0000AA">new</font> MidiEvent(msg, currentTick));
<font color="#555555">047 </font>        currentTick += STAKKATO; <a name="ame2.c"></a>
<font color="#555555">048 </font>      }
<font color="#555555">049 </font>    }
<font color="#555555">050 </font>    <font color="#00AA00">//Sequencer und Synthesizer initialisieren</font>
<font color="#555555">051 </font>    Sequencer sequencer = MidiSystem.getSequencer(); <a name="ame2.d"></a>
<font color="#555555">052 </font>    Transmitter trans = sequencer.getTransmitter();
<font color="#555555">053 </font>    Synthesizer synth = MidiSystem.getSynthesizer();
<font color="#555555">054 </font>    Receiver rcvr = synth.getReceiver();
<font color="#555555">055 </font>    <font color="#00AA00">//Beide &ouml;ffnen und verbinden</font>
<font color="#555555">056 </font>    sequencer.open();
<font color="#555555">057 </font>    synth.open();
<font color="#555555">058 </font>    trans.setReceiver(rcvr);
<font color="#555555">059 </font>    <font color="#00AA00">//Sequence abspielen</font>
<font color="#555555">060 </font>    sequencer.setSequence(seq);
<font color="#555555">061 </font>    sequencer.setTempoInBPM(145);
<font color="#555555">062 </font>    sequencer.start();
<font color="#555555">063 </font>    <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
<font color="#555555">064 </font>      <font color="#0000AA">try</font> {
<font color="#555555">065 </font>        Thread.sleep(100);
<font color="#555555">066 </font>      } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">067 </font>        <font color="#00AA00">//nothing</font>
<font color="#555555">068 </font>      }
<font color="#555555">069 </font>      <font color="#0000AA">if</font> (!sequencer.isRunning()) {
<font color="#555555">070 </font>        <font color="#0000AA">break</font>;
<font color="#555555">071 </font>      }
<font color="#555555">072 </font>    }
<font color="#555555">073 </font>    <font color="#00AA00">//Sequencer anhalten und Ger&auml;te schlie&szlig;en</font>
<font color="#555555">074 </font>    sequencer.stop();
<font color="#555555">075 </font>    sequencer.close();
<font color="#555555">076 </font>    synth.close();
<font color="#555555">077 </font>  }
<font color="#555555">078 </font>
<font color="#555555">079 </font>  <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
<font color="#555555">080 </font>  {
<font color="#555555">081 </font>    <font color="#0000AA">try</font> {
<font color="#555555">082 </font>      playAlleMeineEntchen();
<font color="#555555">083 </font>    } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">084 </font>      e.printStackTrace();
<font color="#555555">085 </font>      System.exit(1);
<font color="#555555">086 </font>    }
<font color="#555555">087 </font>    System.exit(0);
<font color="#555555">088 </font>  }
<font color="#555555">089 </font>}</pre>
</font>
</td>
<td valign=top align=right>
<a href="../examples/Listing4903.java"><font color="#000055" size=-1>Listing4903.java</font></a></td>
</tr>
</table>
<i>
Listing 49.3: Alle meine Entchen mit dem Sequenzer</i></p>

<p>
Die Partiturdaten stimmen mit denen des vorigen Beispiels &uuml;berein,
werden allerdings anders verwendet. Zun&auml;chst wird ab <a href="k100310.html#ame2.a">Zeile 027</a>
eine <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
mit einem einzelnen <a href="index_t.html#ixb102714"><font color=#000080><tt>Track</tt></font></a>
angelegt, deren Aufl&ouml;sung 16 Ticks per Viertelnote betr&auml;gt.
Ab <a href="k100310.html#ame2.b">Zeile 038</a> werden die Daten in
<a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a>-Objekte
&uuml;bertragen und dem <a href="index_t.html#ixb102714"><font color=#000080><tt>Track</tt></font></a>
hinzugef&uuml;gt. Anders als im vorigen Beispiel lassen wir die Note
allerdings nicht w&auml;hrend der kompletten Notenl&auml;nge an, sondern
beenden sie <font color="#000077"><tt>STAKKATO</tt></font> Ticks fr&uuml;her
als vorgesehen. Diese Zeit z&auml;hlen wir in <a href="k100310.html#ame2.c">Zeile 047</a>
zu der anschlie&szlig;enden Pause hinzu. Durch diese Ma&szlig;nahme
gehen die Noten nicht direkt ineinander &uuml;ber, sondern werden
mit einem h&ouml;rbaren Abstand gespielt. In <a href="k100310.html#ame2.e">Zeile 034</a>
wird eine <a href="index_s.html#ixb102709"><font color=#000080><tt>ShortMessage</tt></font></a>
zur Programmumschaltung generiert, um Kanal 0 auf Instrument 48 umzuschalten.
Dadurch erklingt die Sequenz nicht mit einem Piano- sondern mit einem
Streichersound. 

<p>
Ab <a href="k100310.html#ame2.d">Zeile 051</a> werden <a href="index_s.html#ixb102707"><font color=#000080><tt>Sequencer</tt></font></a>
und <a href="index_s.html#ixb102706"><font color=#000080><tt>Synthesizer</tt></font></a>
initialisiert und miteinander verbunden. Anschlie&szlig;end wird die
<a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
an den Sequenzer &uuml;bergeben, die Abspielgeschwindigkeit eingestellt
und das St&uuml;ck gespielt. In der nachfolgenden Schleife wartet
das Programm durch wiederholten Aufruf von <a href="index_i.html#ixb102692"><font color=#000080><tt>isRunning</tt></font></a>,
bis die Sequenz vollst&auml;ndig abgespielt ist. Anschlie&szlig;end
stoppt es den Sequenzer und schlie&szlig;t alle Ger&auml;te. 

<!-- Section -->

<a name="mididateien"></a>
<h3>49.3.5 Zugriff auf Midi-Dateien </h3>


<!-- Section -->
<a name="sectlevel4id049003005001"></a>
<h4>Lesen und Abspielen einer Midi-Datei </h4>

<p>
Als letztes Beispiel zum Thema Midi wollen wir uns ansehen, wie eine
Midi-Datei gelesen und abgespielt werden kann. Dazu ben&ouml;tigen
wir nur noch eine zus&auml;tzliche Methode, n&auml;mlich <a name="ixa103635"><a href="index_g.html#ixb102735"><font color=#000080><tt>getSequence</tt></font></a></a>
aus der Klasse <a href="index_m.html#ixb102702"><font color=#000080><tt>MidiSystem</tt></font></a>:
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public static Sequence getSequence(File file)
  throws InvalidMidiDataException, IOException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/MidiSystem.html" onClick="this.href=getApiDoc('javax.sound.midi.MidiSystem')"><font color="#660066" size=-1>javax.sound.midi.MidiSystem</font></a></td>
</tr>
</table>

<p>
<a href="index_g.html#ixb102735"><font color=#000080><tt>getSequence</tt></font></a>
erwartet ein <a href="index_f.html#ixb100973"><font color=#000080><tt>File</tt></font></a>-Objekt
als Argument, mit dem die abzuspielende Midi-Datei angegeben wird.
Es liefert als R&uuml;ckgabewert eine <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>,
die an den Sequenzer &uuml;bergeben und von diesem abgespielt werden
kann. Ein Beispielprogramm zur Widergabe einer Midi-Datei ist nun
sehr einfach zu konstruieren. Mit Ausnahme der expliziten Konstruktion
der <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
entspricht es vollkommen dem Beispielprogramm des vorigen Abschnitts:
<a name="ame3"></a>

<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
<tr>
<td valign=top>
<font color="#000055">
<pre>
<font color="#555555">001 </font><font color="#00AA00">/* Listing4904.java */</font>
<font color="#555555">002 </font>
<font color="#555555">003 </font><font color="#0000AA">import</font> java.io.*;
<font color="#555555">004 </font><font color="#0000AA">import</font> javax.sound.midi.*;
<font color="#555555">005 </font>
<font color="#555555">006 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> Listing4904
<font color="#555555">007 </font>{
<font color="#555555">008 </font>  <font color="#0000AA">private</font> <font color="#0000AA">static</font> <font color="#006699">void</font> playMidiFile(String name)
<font color="#555555">009 </font>  <font color="#0000AA">throws</font> Exception
<font color="#555555">010 </font>  {
<font color="#555555">011 </font>    <font color="#00AA00">//Sequencer und Synthesizer initialisieren</font>
<font color="#555555">012 </font>    Sequencer sequencer = MidiSystem.getSequencer();
<font color="#555555">013 </font>    Transmitter trans = sequencer.getTransmitter();
<font color="#555555">014 </font>    Synthesizer synth = MidiSystem.getSynthesizer();
<font color="#555555">015 </font>    Receiver rcvr = synth.getReceiver();
<font color="#555555">016 </font>    <font color="#00AA00">//Beide &ouml;ffnen und verbinden</font>
<font color="#555555">017 </font>    sequencer.open();
<font color="#555555">018 </font>    synth.open();
<font color="#555555">019 </font>    trans.setReceiver(rcvr);
<font color="#555555">020 </font>    <font color="#00AA00">//Sequence lesen und abspielen</font>
<font color="#555555">021 </font>    Sequence seq = MidiSystem.getSequence(<font color="#0000AA">new</font> File(name));
<font color="#555555">022 </font>    sequencer.setSequence(seq);
<font color="#555555">023 </font>    sequencer.setTempoInBPM(145);
<font color="#555555">024 </font>    sequencer.start();
<font color="#555555">025 </font>    <font color="#0000AA">while</font> (<font color="#006699">true</font>) {
<font color="#555555">026 </font>      <font color="#0000AA">try</font> {
<font color="#555555">027 </font>        Thread.sleep(100);
<font color="#555555">028 </font>      } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">029 </font>        <font color="#00AA00">//nothing</font>
<font color="#555555">030 </font>      }
<font color="#555555">031 </font>      <font color="#0000AA">if</font> (!sequencer.isRunning()) {
<font color="#555555">032 </font>        <font color="#0000AA">break</font>;
<font color="#555555">033 </font>      }
<font color="#555555">034 </font>    }
<font color="#555555">035 </font>    <font color="#00AA00">//Sequencer anhalten und Ger&auml;te schlie&szlig;en</font>
<font color="#555555">036 </font>    sequencer.stop();
<font color="#555555">037 </font>    sequencer.close();
<font color="#555555">038 </font>    synth.close();
<font color="#555555">039 </font>  }
<font color="#555555">040 </font>
<font color="#555555">041 </font>  <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
<font color="#555555">042 </font>  {
<font color="#555555">043 </font>    <font color="#0000AA">try</font> {
<font color="#555555">044 </font>      playMidiFile(args[0]);
<font color="#555555">045 </font>    } <font color="#0000AA">catch</font> (Exception e) {
<font color="#555555">046 </font>      e.printStackTrace();
<font color="#555555">047 </font>      System.exit(1);
<font color="#555555">048 </font>    }
<font color="#555555">049 </font>    System.exit(0);
<font color="#555555">050 </font>  }
<font color="#555555">051 </font>}</pre>
</font>
</td>
<td valign=top align=right>
<a href="../examples/Listing4904.java"><font color="#000055" size=-1>Listing4904.java</font></a></td>
</tr>
</table>
<i>
Listing 49.4: Abspielen einer Midi-Datei</i></p>

<p>
Das Programm erwartet in der Kommandozeile den Namen der abzuspielenden
Midi-Datei. Wird es mit der (ebenfalls im Verzeichnis der Beispieldateien
befindlichen) Datei <font color="#660099">ame.mid</font> als Argument
aufgerufen, ert&ouml;nt das altbekannte &#187;Alle meine Entchen&#171;.


<!-- Section -->
<a name="sectlevel4id049003005002"></a>
<h4>Abspeichern einer Sequenz in einer Midi-Datei </h4>

<p>
Das Abspeichern einer <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
in einer Midi-Datei ist fast so einfach wie ihr Abspielen. Die Klasse
<a href="index_m.html#ixb102702"><font color=#000080><tt>MidiSystem</tt></font></a>
besitzt dazu eine Methode <a href="index_w.html#ixb100959"><font color=#000080><tt>write</tt></font></a>,
die drei Parameter erwartet: 
<p>
<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#EEFFCC">
<tr>
<td valign=top width=100%>
<font color="#660066">
<pre>
public static int write(Sequence in, int type, File out)
  throws IOException
</pre>
</font>
</td>
<td valign=top>
<a href="../jdkdocs/api/javax/sound/midi/MidiSystem.html" onClick="this.href=getApiDoc('javax.sound.midi.MidiSystem')"><font color="#660066" size=-1>javax.sound.midi.MidiSystem</font></a></td>
</tr>
</table>

<p>
Als erstes Argument wird die zu speichernde <a href="index_s.html#ixb102713"><font color=#000080><tt>Sequence</tt></font></a>
&uuml;bergeben, als zweites der Midi-Dateityp und als letztes ein
<a href="index_f.html#ixb100973"><font color=#000080><tt>File</tt></font></a>-Objekt
mit dem Namen der Ausgabedatei. F&uuml;r einfache Experimente kann
als Midi-Dateityp einfach 0 &uuml;bergeben werden. Ein Array mit allen
unterst&uuml;tzten Dateitypen kann durch Aufruf von <a name="ixa103636"><a href="index_g.html#ixb102736"><font color=#000080><tt>getMidiFileTypes</tt></font></a></a>
beschafft werden. 
<hr>
<table border=0 cellpadding=0 cellspacing=1 width="100%">
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html">&nbsp;Titel&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html">&nbsp;Inhalt&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html">&nbsp;Suchen&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html">&nbsp;Index&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()">&nbsp;DOC&nbsp;</a>
<td align="right">Handbuch der Java-Programmierung, 5. Auflage, Addison
Wesley, Version 5.0.1
<tr bgcolor="#EEFFCC">
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100307.html">&nbsp;&lt;&lt;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100309.html">&nbsp;&nbsp;&lt;&nbsp;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100311.html">&nbsp;&nbsp;&gt;&nbsp;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="k100312.html">&nbsp;&gt;&gt;&nbsp;</a>
<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()">&nbsp;API&nbsp;</a>
<td align="right">&copy; 1998, 2007 Guido Kr&uuml;ger &amp; Thomas
Stark, <a href="http://www.javabuch.de">http://www.javabuch.de</a>
</table>
<a name="endofbody"></a>
</body>
</html>