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