1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20
21 miditrace.c - Midi audio synchronized tracer
22 Written by Masanao Izumo <mo@goice.co.jp>
23 */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #ifdef __POCC__
30 #include <sys/types.h>
31 #endif //for off_t
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif /* HAVE_UNISTD_H */
36 #include <stdlib.h>
37
38 #ifndef NO_STRING_H
39 #include <string.h>
40 #else
41 #include <strings.h>
42 #endif
43
44 #include "timidity.h"
45 #include "common.h"
46 #include "instrum.h"
47 #include "playmidi.h"
48 #include "output.h"
49 #include "controls.h"
50 #include "miditrace.h"
51 #include "wrd.h"
52 #include "aq.h"
53
54 enum trace_argtypes
55 {
56 ARG_VOID,
57 ARG_INT,
58 ARG_INT_INT,
59 ARG_CE,
60 ARGTIME_VP,
61 };
62
63 typedef struct _MidiTraceList
64 {
65 int32 start; /* Samples to start */
66 int argtype; /* Argument type */
67
68 union { /* Argument */
69 int args[2];
70 uint16 ui16;
71 CtlEvent ce;
72 void *v;
73 } a;
74
75 union { /* Handler function */
76 void (*f0)(void);
77 void (*f1)(int);
78 void (*f2)(int, int);
79 void (*fce)(CtlEvent *ce);
80 void (*fv)(void *);
81 } f;
82
83 struct _MidiTraceList *next; /* Chain link next node */
84 } MidiTraceList;
85
86
87 MidiTrace midi_trace;
88 extern int32 current_sample;
89
new_trace_node(void)90 static MidiTraceList *new_trace_node(void)
91 {
92 MidiTraceList *p;
93
94 if(midi_trace.free_list == NULL)
95 p = (MidiTraceList *)new_segment(&midi_trace.pool,
96 sizeof(MidiTraceList));
97 else
98 {
99 p = midi_trace.free_list;
100 midi_trace.free_list = midi_trace.free_list->next;
101 }
102 return p;
103 }
104
reuse_trace_node(MidiTraceList * p)105 static void reuse_trace_node(MidiTraceList *p)
106 {
107 p->next = midi_trace.free_list;
108 midi_trace.free_list = p;
109 }
110
trace_start_time(void)111 static int32 trace_start_time(void)
112 {
113 if(play_mode->flag & PF_CAN_TRACE)
114 return current_sample;
115 return -1;
116 }
117
run_midi_trace(MidiTraceList * p)118 static void run_midi_trace(MidiTraceList *p)
119 {
120 if(!ctl->opened)
121 return;
122
123 switch(p->argtype)
124 {
125 case ARG_VOID:
126 p->f.f0();
127 break;
128 case ARG_INT:
129 p->f.f1(p->a.args[0]);
130 break;
131 case ARG_INT_INT:
132 p->f.f2(p->a.args[0], p->a.args[1]);
133 break;
134 case ARGTIME_VP:
135 p->f.fv(p->a.v);
136 break;
137 case ARG_CE:
138 p->f.fce(&p->a.ce);
139 break;
140 }
141 }
142
midi_trace_setfunc(MidiTraceList * node)143 static MidiTraceList *midi_trace_setfunc(MidiTraceList *node)
144 {
145 MidiTraceList *p;
146
147 if(!ctl->trace_playing || node->start < 0)
148 {
149 run_midi_trace(node);
150 return NULL;
151 }
152
153 p = new_trace_node();
154 *p = *node;
155 p->next = NULL;
156
157 if(midi_trace.head == NULL)
158 midi_trace.head = midi_trace.tail = p;
159 else
160 {
161 midi_trace.tail->next = p;
162 midi_trace.tail = p;
163 }
164
165 return p;
166 }
167
push_midi_trace0(void (* f)(void))168 void push_midi_trace0(void (*f)(void))
169 {
170 MidiTraceList node;
171 if(f == NULL)
172 return;
173 memset(&node, 0, sizeof(node));
174 node.start = trace_start_time();
175 node.argtype = ARG_VOID;
176 node.f.f0 = f;
177 midi_trace_setfunc(&node);
178 }
179
push_midi_trace1(void (* f)(int),int arg1)180 void push_midi_trace1(void (*f)(int), int arg1)
181 {
182 MidiTraceList node;
183 if(f == NULL)
184 return;
185 memset(&node, 0, sizeof(node));
186 node.start = trace_start_time();
187 node.argtype = ARG_INT;
188 node.f.f1 = f;
189 node.a.args[0] = arg1;
190 midi_trace_setfunc(&node);
191 }
192
push_midi_trace2(void (* f)(int,int),int arg1,int arg2)193 void push_midi_trace2(void (*f)(int, int), int arg1, int arg2)
194 {
195 MidiTraceList node;
196 if(f == NULL)
197 return;
198 memset(&node, 0, sizeof(node));
199 node.start = trace_start_time();
200 node.argtype = ARG_INT_INT;
201 node.f.f2 = f;
202 node.a.args[0] = arg1;
203 node.a.args[1] = arg2;
204 midi_trace_setfunc(&node);
205 }
206
push_midi_trace_ce(void (* f)(CtlEvent *),CtlEvent * ce)207 void push_midi_trace_ce(void (*f)(CtlEvent *), CtlEvent *ce)
208 {
209 MidiTraceList node;
210 if(f == NULL)
211 return;
212 memset(&node, 0, sizeof(node));
213 node.start = trace_start_time();
214 node.argtype = ARG_CE;
215 node.f.fce = f;
216 node.a.ce = *ce;
217 midi_trace_setfunc(&node);
218 }
219
push_midi_time_vp(int32 start,void (* f)(void *),void * vp)220 void push_midi_time_vp(int32 start, void (*f)(void *), void *vp)
221 {
222 MidiTraceList node;
223 if(f == NULL)
224 return;
225 memset(&node, 0, sizeof(node));
226 node.start = start;
227 node.argtype = ARGTIME_VP;
228 node.f.fv = f;
229 node.a.v = vp;
230 midi_trace_setfunc(&node);
231 }
232
trace_loop(void)233 int32 trace_loop(void)
234 {
235 int32 cur;
236 int ctl_update;
237 static int lasttime = -1;
238
239 if(midi_trace.trace_loop_hook != NULL)
240 midi_trace.trace_loop_hook();
241
242 if(midi_trace.head == NULL)
243 return 0;
244
245 if((cur = current_trace_samples()) == -1 || !ctl->trace_playing)
246 cur = 0x7fffffff; /* apply all trace event */
247
248 ctl_update = 0;
249 while(midi_trace.head && cur >= midi_trace.head->start
250 && cur > 0) /* privent flying start */
251 {
252 MidiTraceList *p;
253
254 p = midi_trace.head;
255 run_midi_trace(p);
256 if(p->argtype == ARG_CE)
257 ctl_update = 1;
258 midi_trace.head = midi_trace.head->next;
259 reuse_trace_node(p);
260 }
261
262 if(ctl_update)
263 ctl_mode_event(CTLE_REFRESH, 0, 0, 0);
264
265 if(midi_trace.head == NULL)
266 {
267 midi_trace.tail = NULL;
268 return 0; /* No more tracing */
269 }
270
271 if(!ctl_update)
272 {
273 if(lasttime == cur)
274 midi_trace.head->start--; /* avoid infinite loop */
275 lasttime = cur;
276 }
277
278 return 1; /* must call trace_loop() continued */
279 }
280
trace_offset(int offset)281 void trace_offset(int offset)
282 {
283 midi_trace.offset = offset;
284 }
285
trace_flush(void)286 void trace_flush(void)
287 {
288 midi_trace.flush_flag = 1;
289 wrd_midi_event(WRD_START_SKIP, WRD_NOARG);
290 while(midi_trace.head)
291 {
292 MidiTraceList *p;
293
294 p = midi_trace.head;
295 run_midi_trace(p);
296 midi_trace.head = midi_trace.head->next;
297 reuse_trace_node(p);
298 }
299 wrd_midi_event(WRD_END_SKIP, WRD_NOARG);
300 reuse_mblock(&midi_trace.pool);
301 midi_trace.head = midi_trace.tail = midi_trace.free_list = NULL;
302 ctl_mode_event(CTLE_REFRESH, 0, 0, 0);
303 midi_trace.flush_flag = 0;
304 }
305
set_trace_loop_hook(void (* f)(void))306 void set_trace_loop_hook(void (* f)(void))
307 {
308 midi_trace.trace_loop_hook = f;
309 }
310
current_trace_samples(void)311 int32 current_trace_samples(void)
312 {
313 int32 sp;
314 if((sp = aq_samples()) == -1)
315 return -1;
316 return midi_trace.offset + aq_samples();
317 }
318
init_midi_trace(void)319 void init_midi_trace(void)
320 {
321 memset(&midi_trace, 0, sizeof(midi_trace));
322 init_mblock(&midi_trace.pool);
323 }
324
trace_wait_samples(void)325 int32 trace_wait_samples(void)
326 {
327 int32 s;
328
329 if(midi_trace.head == NULL)
330 return -1;
331 if((s = current_trace_samples()) == -1)
332 return 0;
333 s = midi_trace.head->start - s;
334 if(s < 0)
335 s = 0;
336 return s;
337 }
338