3 <title>crush sequencer
</title>
4 <style type=
"text/css">
5 body
{ font-family: sans-serif
; }
7 ul
{ padding: 0; list-style-type: none
; }
12 <h1>codename: crush sequencer
</h1>
15 <p>It's a midi sequencer. It is a state machine mainly consisting of
16 midi events arranged in time (with some structure convenient for
17 editing) and also some auxilliary machinery to support certain
18 editing operations.
</p>
20 <p>It has two main functions which it carries out concurrently: it
21 plays back the events synchronous with some callback framework,
22 and it allows a client app to make concurrent changes to the sequence.
</p>
25 <p>Think of it as a tape deck with buttons that read and write to
26 the tape (the client app's interface) and two ports for audio out
27 (midi out) and mic input (for recording input). When the tape is
28 playing, or recording, the user has no direct control over the
29 behavior of the I/O port.
</p>
32 <h2>realtime audio:
</h2>
33 <p>To support realtime operation, time consuming processes like memory
34 management are only initiated by actions of the client code, not
35 the I/O callback code.
</p>
38 <h2>features intentionally missing:
</h2>
39 <p>There are some higher level operations a midi sequencer might be
40 expected to have, but they are not provided at this level and
41 should be implemented as a layer on top. The idea here is to only
42 address the complexity of multithreaded audio programming, realtime
43 memory management, low level data consistency, timing, and undo/redo.
</p>
47 <p>This documentation attempt will explain the structure of the events,
48 possible editing operations, the asynchronous i/o interface, and
49 the few extra features of the sequencer (auto cutoff).
</p>
54 <li>the sequencer has zero or more tracks
</li>
55 <li>tracks have chan and port, and contain a sequence of blocks
</li>
56 <li>blocks have length and have one or more references to chunks
</li>
57 <li>chunks have a color and contain a sequence of events
</li>
58 <li>events are basic midi events without channel
</li>
61 <h2>blocks and chunks:
</h2>
62 <p>Blocks may reference more than one chunk, but only one chunk
63 is active at a given time. These are sometimes called
64 layers but they dont have a separate name here except
65 the chunks in the block. Blocks may share chunks, changes
66 to one chunk show up in another block immediately.
</p>
68 <h2>nonstandard api description:
</h2>
69 <p>The api will be described abstractly, but more clearly than a C
70 header file. The C signatures are listed in the seq.h header file.
71 A method listed as X -
> Y is a procedure that takes arguments X and
72 produces Y. The word effects in the Y part is used to signify that
73 using this operation changes the sequencers internal state. Possible
74 memory allocation is not considered an effect. If an operation takes no
75 arguments it is listed without the X -
>. If a value is listed with
76 a ? suffix, it means it may be NULL. The possibility of having no
77 effect at all is not considered to be ?. The possibility of failure to
78 allocate memory is not considered to be ?. See the section on custom
79 memory management. The expression Y + effects is used when a procedure
80 results in effects and values. in C effects are not values. Read + as
81 'in addition to'. when there are more than one result values, the
82 C api will use passed-in pointers to write some of the results.
</p>
84 <h2>client interface:
</h2>
85 <p>The 'gui thread', client code that provides a user interface to the
86 sequence, has several operations available to support playback, editing,
87 undo/redo, time config, looping (between two global static times),
88 outputting an immediate event (not scheduled), and reading back data
89 for display purposes.
</p>
93 seq_add_track :: effects
94 seq_delete_track :: track -
> effects
95 seq_insert_block :: (track, tick, length, chunk) -
> effects
96 seq_copy_block :: (block, track, tick) -
> effects
97 seq_resize_block :: (block,length) -
> effects
98 seq_delete_block :: (track,block) -
> effects
99 seq_push_chunk :: (block,chunk) -
> effects
100 seq_rrotate_chunk :: block -
> effects
101 seq_lrotate_chunk :: block -
> effects
102 seq_insert_event :: (chunk,tick,type,u,v) -
> effects
103 seq_delete_event :: (chunk,event) --
> effects
104 seq_accept_recording :: effects
109 seq_play :: enable -
> effects
111 seq_seek :: tick -
> effects
113 seq_record :: enable -
> effects
114 seq_set_record_track :: index -
> effects
115 seq_loop :: enable -
> effects
116 seq_loop_limits :: (tick1,tick2) -
> effects
117 seq_time_config :: (srate, tpb, bpm) -
> effects
118 seq_all_notes_off :: effects
123 seq_init :: (alloc?,free?,oom?) -
> effects
124 seq_uninit :: effects
127 seq_commit :: effects
128 seq_clear_all :: effects
129 seq_instant :: (track,type,u,v) -
> effects
130 seq_mk_chunk :: chunk
135 seq_layer_number :: block -
> index
136 seq_walk_tracks :: effects
137 seq_next_track :: track? + effects
138 seq_walk_blocks :: track -
> effects
139 seq_next_block :: block? + effects
140 seq_walk_events :: chunk -
> effects
141 seq_next_event :: event? + effects
147 <h2>sequence data is public:
</h2>
148 <p>The structures which represent the tracks, blocks, chunks and events
149 are publically exposed to avoid a giant interface to simply read the
150 fields. Some fields are meant to be read/write to avoid a get/set
151 interface. These are listed in the header file. Some fields are
152 better not used by client code, these are not listed as read nor
153 read/write in the header file.
</p>
155 <h2>custom memory management:
</h2>
156 <p>The client code may request memory be dynamically allocated. seq_init
157 accepts up to three routines which handle this as the client code sees
158 fit. alloc should deliver a pointer to newly allocated memory of the
159 desired size. free should release the memory pointed to by the argument.
160 oom is a routine to handle the case where alloc fails. By passing NULL
161 in for any of these, the default allocator will be used (std malloc).
162 Please provide both alloc and free or neither of them because your
163 custom allocator is probably not compatible with the default free and
164 vice versa. The default oom handler writes a message to stderr and
165 exits with code
13, so its compatible with anything.
</p>
167 <p>oom may either find more memory and report success, it may report
168 failure, or it may choose to not return (exit the program). If it
169 reports failure, then the internal sequencer will use emergency static
170 allocated storage in order to return from the current operation without
171 incident. After this you are guarantee not to have a reliable sequencer,
172 so the oom routine should consider cutting off the client code from the
173 sequencer a high priority. If using the tape deck analogy from above,
174 think of oom failure as either causing the tape deck itself to explode,
175 or to leave it intact, but might explode the next time it is operated.
</p>
180 <h2>asynchronous i/o interface:
</h2>
181 <p>The 'audio thread' which represents the cable carrying playback
182 events and delivering input events to the recorder takes the form
183 of two operations:
</p>
186 seq_advance :: sample_count -
> (status, nused, port, type, chan, u, v) + effects
187 seq_record_event :: (type, chan, u, v) -
> effects
190 <p>The audio driver charged with handling the next N samples of sequence
191 should use seq_advance to advance the sequencer and return the next
192 event if any. You know when there are no events left by looking at the
193 status code. The number of samples actually advanced is returned. If this
194 number if less than N then the driver code needs to continue extracting
197 <p>The audio driver with incoming midi events should dump them to the
198 sequencer with seq_record_event. The module will internally decide
199 to ignore them or to record them. Because editing of the sequence
200 might cause memory management record will be deferred until the client
201 thread issues a periodic 'accept_recording' signal. accept_recording
202 is only necessary if recording has been enabled by the client code.
203 When recording is disabled, any pending events will be expunged, future
210 <h2>auto-cutoff:
</h2>
211 <p>This sequencer comes with a fancy auto note-off mechanism which
212 will send note offs for any note ons which have not be cut when
213 the client code stops playback. It will also auto cut notes which
214 are on during editting operations that could result in stuck notes.
215 this feature is tricky so sometimes more notes are cut than necessary.
</p>
219 <p>Editting of sequence events can be undone. To support higher level
220 operations that are undone with fewer steps, undoing works with
221 commits. After completing an operation you wish to be able to totally
222 undo, commit the changes. Redo will redo all changes until a commit.
223 editing will clear any redoable actions on the stack.
</p>