~ubuntu-branches/ubuntu/breezy/kdemultimedia/breezy

« back to all changes in this revision

Viewing changes to arts/midi/README.midi

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2005-03-24 04:48:58 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050324044858-8ff88o9jxej6ii3d
Tags: 4:3.4.0-0ubuntu3
Add kubuntu_02_hide_arts_menu_entries.diff to hide artsbuilder and artscontrol k-menu entries

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Midi, Audio and Synchronization:
 
2
================================
 
3
 
 
4
1. Introduction
 
5
2. The midi manager
 
6
3. Midi synchronization
 
7
4. Audio timestamping and synchronization
 
8
5. Example code
 
9
 
 
10
 
 
11
  1. Introduction
 
12
  ---------------
 
13
 
 
14
Since aRts-1.0 (as shipped with KDE3.0), aRts provides a lot more
 
15
infrastructure to deal with midi, audio, and their synchronization. The main
 
16
goal is to provide a unified interface between sequencers (or other programs
 
17
that require notes or audio tracks to be played at certain given time stamps)
 
18
and underlying software/hardware that can play notes/audio tracks.
 
19
 
 
20
Currently, there exist five distinct destinations that aRts supports, which
 
21
can all be used at the same time or individually, that is:
 
22
 
 
23
 * aRts synthetic midi instruments
 
24
 * ALSA-0.5
 
25
 * ALSA-0.9
 
26
 * OSS
 
27
 * other aRts modules (including but not limited to the playback/recording
 
28
   of audio tracks)
 
29
 
 
30
  2. The midi manager
 
31
  -------------------
 
32
 
 
33
The midi manager is the basic component that connects between applications
 
34
that supply/record midi data, and devices that process midi data. Devices
 
35
might be both, virtual (as in software synthesis) or real (as in hardware
 
36
devices).
 
37
 
 
38
From the view of the midi manager, all event streams correspond to one midi
 
39
client. So, a midi client might be an application (such as a sequencer) that
 
40
provides events, or an ALSA hardware device that consumes events. If there
 
41
are multiple event streams, they correspond to multiple clients. That is,
 
42
if an application wishes to play three different midi tracks, one over ALSA,
 
43
and two over two different synthetic instruments, it needs to register itself
 
44
three times, with three different clients.
 
45
 
 
46
The midi managers job is to connect midi clients (as in event streams). It
 
47
maintains a list of connections that the user can modify with an application
 
48
like artscontrol. Applications could also, if they wish so, modify this
 
49
connection list. 
 
50
 
 
51
As a use case, we'll consider the following: you want to write a sequencer
 
52
application that plays back two different tracks to two different devices.
 
53
You want the user to be able to select these devices in a drop down box for
 
54
each track.
 
55
 
 
56
1) getting a list of choices:
 
57
 
 
58
First, you will want to obtain a list of choices which the user could possibly
 
59
connect your tracks to. You do so by reading the
 
60
 
 
61
interface MidiManager { // SINGLETON: Arts_MidiManager
 
62
    /**
 
63
     * a list of clients
 
64
     */
 
65
    readonly attribute sequence<MidiClientInfo> clients;
 
66
 
 
67
        //...
 
68
};
 
69
 
 
70
attribute. The three fields of each client that are interesting for you are
 
71
 
 
72
struct MidiClientInfo {
 
73
        long ID;
 
74
 
 
75
        //...
 
76
 
 
77
        MidiClientDirection direction;
 
78
        MidiClientType type;
 
79
        string title;
 
80
};
 
81
 
 
82
You would list those devices in the dropdown box that are of the appropriate
 
83
direction, which is mcdRecord, as you would want a client that receives midi
 
84
events (this might be confusing, but you look from the view of the client).
 
85
 
 
86
Then, there is the type field, which tells you whether the client is a device-
 
87
like thing (like a synthetic instrument), or another application (like another
 
88
application currently recording a track). While it might not be an impossible
 
89
setup that you send events between two applications, usually users will choose
 
90
such clients that have mctDestination as type.
 
91
 
 
92
Finally, you can list the titles in a drop down box, and keep the ID for making
 
93
a connection later.
 
94
 
 
95
2) registering clients:
 
96
 
 
97
You will need to register one client for each track. Use
 
98
 
 
99
        /**
 
100
         * add a client
 
101
     *
 
102
         * this creates a new MidiManagerClient
 
103
         */ 
 
104
        MidiClient addClient(MidiClientDirection direction, MidiClientType type,
 
105
                                                        string title, string autoRestoreID);
 
106
 
 
107
to do so.
 
108
 
 
109
3) connecting:
 
110
 
 
111
As you probably don't want your sequencer user to use artscontrol to setup
 
112
connections between your tracks and the devices, you will need to connect
 
113
your clients to the hardware devices for playing something.
 
114
 
 
115
You can connect clients to their appropriate destinations using
 
116
 
 
117
        /**
 
118
         * connect two clients
 
119
         */
 
120
        void connect(long clientID, long destinationID);
 
121
 
 
122
and
 
123
 
 
124
        /**
 
125
         * disconnect two clients
 
126
         */
 
127
        void disconnect(long clientID, long destinationID);
 
128
 
 
129
Keep in mind that a client might be connected to more than one destination
 
130
at the same time, so that you will need to disconnect the old destination
 
131
before connecting the new one.
 
132
 
 
133
4) playing events:
 
134
 
 
135
You can now play events to the tracks, using each client's
 
136
 
 
137
        MidiPort addOutputPort();
 
138
 
 
139
function for getting a port where you can send events to. However, you will
 
140
also need to ensure that the events will get synchronized as soon as you are
 
141
playing back events to different devices. Read the next section for details
 
142
on this.
 
143
 
 
144
  3. Midi synchronization
 
145
  -----------------------
 
146
 
 
147
As soon as you are writing a real sequencer, you might want to output to more
 
148
than one midi device at a time. For instance, you might want to let some of
 
149
your midi events be played by aRts synthesis, while others should be sent
 
150
over the external midi port.
 
151
 
 
152
To support this setup, a new interface called MidiSyncGroup has been added. To
 
153
output midi events synchronized over more than one port, you proceed as follows:
 
154
 
 
155
a) you obtain a reference to the midi manager object
 
156
 
 
157
   MidiManager midiManager = DynamicCast(Reference("global:Arts_MidiManager"));
 
158
   if(midiManager.isNull()) arts_fatal("midimanager is null");
 
159
 
 
160
b) you create a midi synchronization group which will ensure that the
 
161
   timestamps of your midi events will be synchronized
 
162
   
 
163
   MidiSyncGroup syncGroup = midiManager.addSyncGroup();
 
164
 
 
165
c) you add a client to the midi manager for each port you want to output
 
166
   midi data over
 
167
 
 
168
   MidiClient client = midiManager.addClient(mcdPlay, mctApplication, "midisynctest", "midisynctest");
 
169
   MidiClient client2 = midiManager.addClient(mcdPlay, mctApplication, "midisynctest2", "midisynctest2");
 
170
 
 
171
d) you insert the clients in the synchronization group
 
172
 
 
173
   syncGroup.addClient(client);
 
174
   syncGroup.addClient(client2);
 
175
 
 
176
e) you create ports for each client as usual
 
177
 
 
178
   MidiPort port = client.addOutputPort();
 
179
   MidiPort port2 = client2.addOutputPort();
 
180
 
 
181
f) at this point, you will need to ensure that the midi clients you created
 
182
   are connected, you can either leave the user with artscontrol for doing
 
183
   this, or use the clients and connect methods of the midiManager object
 
184
   yourself (see use case discussed in previous section)
 
185
 
 
186
g) you output events over the ports as usual
 
187
 
 
188
   /* where t is a suitable TimeStamp */
 
189
   MidiEvent e = MidiEvent(t,MidiCommand(mcsNoteOn|0, notes[np], 100));
 
190
   port.processEvent(e);
 
191
   port2.processEvent(e);
 
192
 
 
193
  4. Audio timestamping and synchronization
 
194
  -----------------------------------------
 
195
 
 
196
Audio in aRts is usually handled as structures consisting of small modules
 
197
that do something. While this model allows you to describe anything you want
 
198
to, from playing a sample to playing a synthetic sequence of notes with a
 
199
synthetic instruments, it doesn't give you any notion of time. More so, if
 
200
you build a large graph of objects, you might need quite some time for this,
 
201
and you will want to have them all started at the same time.
 
202
 
 
203
To solve this issue, an AudioSync interface has been introduced, that allows
 
204
you to start() and stop() either synchronized at a specific point in time.
 
205
 
 
206
Suppose you have two synthesis modules which together play back a sample.
 
207
What can you do to start them at the same time?
 
208
 
 
209
        Synth_PLAY_WAV wav = //... create on server
 
210
        Synth_AMAN_PLAY sap //... create on server
 
211
        AudioSync audioSync = //... create on server
 
212
 
 
213
        wav.filename("/opt/kde3/share/sounds/pop.wav");
 
214
        sap.title("midisynctest2");
 
215
        sap.autoRestoreID("midisynctest2");
 
216
        connect(wav,sap);
 
217
 
 
218
        // this queues back start() to be called atomically later
 
219
        audioSync.queueStart(wav);
 
220
        audioSync.queueStart(sap);
 
221
 
 
222
        // this line is a synchronized version of
 
223
        // wav.start();
 
224
        // sap.start();
 
225
        audioSync.execute();
 
226
 
 
227
You could also play them back at a specific time in the future and query the
 
228
current time using the time and executeAt methods:
 
229
 
 
230
interface AudioSync {
 
231
        /**
 
232
         * the current time
 
233
         */
 
234
        readonly attribute TimeStamp time;
 
235
 
 
236
        //...
 
237
 
 
238
        /**
 
239
         * atomically executes all queued modifications to the flow system
 
240
         * at a given time
 
241
         */
 
242
        void executeAt(TimeStamp timeStamp);
 
243
};
 
244
 
 
245
Finally, to get synchronized midi and audio, you can insert the AudioSync
 
246
object into a midi synchronization group, then their timestamps will be
 
247
synchronized to those of the midi channels.
 
248
 
 
249
  5. Example code
 
250
  ---------------
 
251
 
 
252
An example that illustrates most things discussed in this document is
 
253
midisynctest.cc, which plays back two synchronized midi streams and samples.
 
254
Note that you might want to change the source code, as it hardcodes the
 
255
location of the .wav file.
 
256
 
 
257
 
 
258
Questions and comments are welcome.
 
259
 
 
260
Stefan Westerfeld
 
261
stefan@space.twc.de